#!BPY

""" Registration info for Blender menus: <- these words are ignored
Name: 'Ipo_Tools'
Blender: 248
Group: 'Animation'
Tip: 'tools for batch operations on ipos of objects and armatures, also for cleaning data.'
"""

__author__ = "Vilem Novak"
__url__ = ("http://wiki.blender.org/index.php/Scripts/Manual/Animation/IPO_Tools")
__version__ = "0.10 - 2009"

__bpydoc__ = """\
Tools for Batch operations on IPO keys.

"""

#===============================================#
# ipo cleanup script  by Vilem Novak            #
#                                               #
# if you have any questions about this script   #
# email me pildanovak at post dot cz            #
#                                               #
#===============================================#

# -------------------------------------------------------------------------- 
# ***** BEGIN GPL LICENSE BLOCK ***** 
# 
# This program is free software; you can redistribute it and/or 
# modify it under the terms of the GNU General Public License 
# as published by the Free Software Foundation; either version 2 
# of the License, or (at your option) any later version. 
# 
# This program is distributed in the hope that it will be useful, 
# but WITHOUT ANY WARRANTY; without even the implied warranty of 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
# GNU General Public License for more details. 
# 
# You should have received a copy of the GNU General Public License 
# along with this program; if not, write to the Free Software Foundation, 
# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. 
# 
# ***** END GPL LICENCE BLOCK ***** 
# -------------------------------------------------------------------------- 


import Blender
from Blender import *
#from Blender.Armature import *
#from Blender.Armature.Bone import *
from Blender.Object import*
from Blender.Scene import *
from Blender.Mathutils import*
from Blender.NMesh import FaceModes,FaceTranspModes
print FaceModes
print FaceTranspModes

scn= Scene.GetCurrent()
ctx= scn.getRenderingContext()
theresold=Draw.Create(0.00001)
onlySlopes=Draw.Create(1)

def interface():
    global theresold,onlySlopes

    BGL.glClearColor(0.5, 0.5, 0.5, 1)
    BGL.glColor3f(1.,1.,1.)
    BGL.glClear(Blender.BGL.GL_COLOR_BUFFER_BIT)

    ####buttons
    Draw.Button("clearIpos", 4, 110, 10, 60, 25,"clear all ipo curves in selected object's Ipos (not in actions)")
    Draw.Button("Exit", 1, 170, 10, 40, 25)
    BGL.glRasterPos2i(150,190)
    Draw.Text("set interpolation:")
    Draw.Button("Linear", 6, 150, 160, 70, 25)
    Draw.Button("Bezier", 7, 150, 130, 70, 25)
    Draw.Button("Constant", 8, 150, 100, 70, 25)

    BGL.glRasterPos2i(10,190)
    Draw.Text("set extrapolation:")
    Draw.Button("Constant", 11, 10, 170, 120, 18)
    Draw.Button("Extrapolation", 12, 10, 150, 120, 18)
    Draw.Button("Cyclic", 13, 10, 130, 120, 18)
    Draw.Button("Cyclic_extrapolation", 14, 10, 110, 120, 18)
    
    Draw.Button("CleanupIpos", 10, 10, 10, 100, 25,"Removes redundant points in the ipo curves using the theresold value (for armatures also for associated actions)")
    theresold = Blender.Draw.Number("theresold", 2, 10, 60, 210, 18, theresold.val, .0000, 10, "differences smaller than this will be cleaned")
    onlySlopes=Draw.Toggle("only slopes", 1000, 10, 40, 100, 18,onlySlopes.val,"if turned on, only points on the slopes of ipocurves will be filtered.")
    


def exit(evt, val):
    if evt == Blender.Draw.QKEY and not val: Blender.Draw.Exit()


def events(event):
    if event==1:
        Draw.Exit()
    if event==4:
        clearIpos()
    if event ==6:
        setType('Linear')
    if event ==7:
        setType('Bezier')
    if event ==8:
        setType('Constant')

    if event ==10:
        cleanupIpos()

    if event ==11:
        setExt('Constant')
    if event ==12:
        setExt('Extrapolation')
    if event ==13:
        setExt('Cyclic')
    if event ==14:
        setExt('Cyclic_extrapolation')
    if event==1000:
        print onlySlopes.val




def extractCurves():#get cruves from all selected objects and armatures
    obj=GetSelected()

    curves=[]
    print 'anikurvy'
    for ob in obj:
        ipo=ob.getIpo()
        if ipo!=None:
            curves.extend(ipo.getCurves())
        #print ob.getType
        if ob.getType()=='Armature':
            print 'object is an armature'
            a = ob.getAction()
            aipos = a.getAllChannelIpos()
            print aipos
            for key in aipos.keys():
                curves.extend(aipos[key].getCurves())
    print 'asponkurvy'
    return curves
    



def cleanupIpos():
    global fsold,onlySlopes
    scn= Scene.GetCurrent()

    oi=0
    curves=extractCurves()
    
    i=0
    print 'starting cleanup'
    total=0
    
    totalp=0
    
    for c in curves:
        t=theresold.val
    
        if c.name[:4]=='Quat':
            t=t/2.0####quaternions get more care in actions, since they are only from -1 to 1 representing 360 degrees
            
        points= c.bezierPoints
        erase=[]
        ##########################
        #stats
        ##########################
        beginarea=0
        arealen=0
        peaks=0
        threses=0
        lthreses=0
        ##########################
        #cleaning
        #############################
        for a in range(1,len(points)-1):
            pt=points[a].pt
            
#                pt1=points[a-1].pt
            pt1=points[beginarea].pt
            pt2=points[a+1].pt

            # the supercondition for distance from slope
            dif=abs((pt1[1]+(pt2[1]-pt1[1])*((pt[0]-pt1[0])/(pt2[0]-pt1[0])))-pt[1])
            #print dif
            thres = dif<t
            littlethres = dif<t/10###littlethres is for very small peaks on straight curves
            peak = (onlySlopes.val) and ((pt1[1]<=pt[1] and pt2[1]<=pt[1]) or (pt1[1]>=pt[1] and pt2[1]>=pt[1]))
            threses+=thres
            lthreses+=littlethres
            peaks+=peak
            if (thres and not peak) or littlethres:
                        erase.append(a)
            else:
                beginarea=a
        erase.reverse()
        total+=len(erase)
        totalp+=len(points)
        for p in erase:    
            c.delBezier(p)
        c.interpolation=IpoCurve.InterpTypes.LINEAR
        c.recalc()
    scn.update()
    
    print 'cleaned up %d out of %d points in %d curves' % (total,totalp,len(curves))
    
    Blender.Window.RedrawAll()
    
    
    
def clearIpos():
    obj=GetSelected()
    for ob in obj:
        ipo=Blender.Ipo.New('Object',ob.name)
        ob.setIpo(ipo)
    Blender.Window.RedrawAll()



def setType(type):
    curves=extractCurves()
    for c in curves:
        c.setInterpolation(type)
        c.recalc()
    Blender.Window.RedrawAll()
class emp:
    pass



def setExt(ext):

    curves=extractCurves()
    for c in curves:
        c.setExtrapolation(ext)
        c.recalc()
                #print 'e'
    Blender.Window.RedrawAll()




Draw.Register(interface,exit,events)