"""
HB_Relax V1.1

Last Modified: 11/2/2016
Works with CINEMA 4D R16.050 and up.
Copyright: Holger Biebrach, www.c4dstuff.com

Name-US: HB_Relax
Description-US: Relax current Selection [SHIFT: Relax Stronger]

If you have a Polygon/Point-Selection the Script will Relax the Selected Components but will keep the outline Points of the Selection
untouched.

Video Tutorial:
https://youtu.be/kQpLqrtGfBQ?t=2m29s

Name-DE: HB_Relax
Description-DE: Entspannt die selektierten Elemente [SHIFT: Entspannt stärker]

ChangeLog:

11/2/2016 v1.1
- Fixed a Bug where the Object would jump to zero

1/1/2016 v1.0 Release Version

"""

import c4d
from c4d import gui, documents, plugins, utils


def deletetags(obj): # Scan Tags on Object
    
    n       = 1 
    
    tags    = obj.GetTags()

    for tag in tags:
        if not tag: continue
        tagtype = tag.GetType()
   
        
        if tag.GetName()=="tempsel":
            doc.AddUndo(c4d.UNDOTYPE_DELETE, tag)
            tag.Remove()
            c4d.EventAdd()




def RemoveChildren(objlist):
    
    for obj in objlist:
        doc.AddUndo(c4d.UNDOTYPE_DELETE, obj)
        obj.Remove()
        
        
    
    c4d.EventAdd()    
    return

def InsertChildren(objlist,root):
    
    
    for obj in objlist:
        
        obj.InsertUnder(root)
        doc.AddUndo(c4d.UNDOTYPE_NEW, obj)
        
        
    c4d.EventAdd()    
    return






def main():
    
    doc.StartUndo()
    
    selobj=doc.GetSelection()
    
    if len(selobj)>1 or len(selobj)==0 : #ERROR
        
        gui.MessageDialog("Select one Object and no Tag!")
        return


    bc = c4d.BaseContainer()
    c4d.gui.GetInputState(c4d.BFM_INPUT_KEYBOARD,c4d.BFM_INPUT_CHANNEL,bc) #Modifier Key pressed?
    
    if bc[c4d.BFM_INPUT_QUALIFIER] ==1:
       SHIFT=True
       if len(selobj)==2:
           gui.MessageDialog("Select one Object and no Tag!")
           return     
    else:
        SHIFT=False


    mode=doc.GetMode()

    obj=selobj[0]
    Pos=obj.GetMg()
    objChildren = obj.GetChildren()
    if doc.GetMode()==7: # is Polymode active? Convert to Pointselection

        c4d.utils.SendModelingCommand(command = c4d.MCOMMAND_SELECTPOLYTOPOINT,
                                    list = [obj],
                                    mode = c4d.MODELINGCOMMANDMODE_POLYGONSELECTION,
                                    bc = c4d.BaseContainer(),
                                    doc = doc)
    

    doc.SetMode(5)#pointmode

 
   
    
    sel = c4d.BaseSelect()
    
    obj.GetPointS().CopyTo(sel)
    

    SmoothDeformer=c4d.BaseObject(1024529)
    SmoothDeformer[c4d.ID_CA_SMOOTHING_DEFORMER_OBJECT_STIFFNESS]=0
    SmoothDeformer[c4d.ID_CA_SMOOTHING_DEFORMER_OBJECT_STRENGTH]=100
    if SHIFT == True:
        SmoothDeformer[c4d.ID_CA_SMOOTHING_DEFORMER_OBJECT_ITERATIONS]=50
        
    else:
        SmoothDeformer[c4d.ID_CA_SMOOTHING_DEFORMER_OBJECT_ITERATIONS]=1
    
    
    c4d.utils.SendModelingCommand(command = c4d.MCOMMAND_SELECTSHRINK,
                                list = [obj],
                                mode = c4d.MODELINGCOMMANDMODE_POINTSELECTION,
                                bc = c4d.BaseContainer(),
                                doc = doc)
                                
                                

    c4d.CallCommand(12552) # Set Selection
    newseltag=doc.GetActiveTag()

    newseltag.SetName("tempsel")
    restag = c4d.BaseTag(5683)
    restag[c4d.RESTRICTIONTAG_NAME_01]="tempsel"
    SmoothDeformer.InsertTag(restag)
    doc.AddUndo(c4d.UNDOTYPE_NEW, restag)
    
    SmoothDeformer.InsertUnder(obj)
    doc.AddUndo(c4d.UNDOTYPE_NEW, SmoothDeformer)
    
    
    #CURRENT STATE TO OBJECT
    CSsettings = c4d.BaseContainer()                 
    NewObj=utils.SendModelingCommand(command = c4d.MCOMMAND_CURRENTSTATETOOBJECT,
                                    list = [obj],
                                    mode = c4d.MODELINGCOMMANDMODE_EDGESELECTION,
                                    bc = CSsettings,
                                    doc = doc,
                                    )
       
        
    
    if NewObj[0].GetType()==c4d.Onull:
        NewObjChild=NewObj[0].GetDown()

        
    else:
        NewObjChild=NewObj[0]

        
    NewObjChild.InsertAfter(obj)
    doc.AddUndo(c4d.UNDOTYPE_NEW, NewObjChild)
    
    NewObjChild.SetMg(Pos)

    
    doc.AddUndo(c4d.UNDOTYPE_CHANGE_SMALL,NewObjChild)
    NewObjChild.SetBit(c4d.BIT_ACTIVE)
    
    ObjChild=NewObjChild.GetDown()
    if ObjChild:
        
        doc.AddUndo(c4d.UNDOTYPE_DELETE, ObjChild)
        ObjChild.Remove()
    
    doc.AddUndo(c4d.UNDOTYPE_DELETE, obj)
    obj.Remove()
    deletetags(NewObjChild)
    
    NewObjChildren=NewObjChild.GetChildren()
    
    RemoveChildren(NewObjChildren)
    
    
    
    other_sel = NewObjChild.GetPointS() 
    
    sel.CopyTo(other_sel)
    
    
    NewObjChild.Message(c4d.MSG_UPDATE)
    InsertChildren(objChildren, NewObjChild)
    
    doc.SetMode(mode)
    doc.EndUndo()
    c4d.EventAdd()



if __name__=='__main__':
    main()
