"""
HB_RoundEdge V1.0

Last Modified: 6/25/2015
Works with CINEMA 4D R16.050 and up.
Copyright: Holger Biebrach, www.c4dstuff.com

Name-US: HB_RoundEdge
Description-US: Smooth current Edge-Selection [SHIFT: Smooth Stronger, CTRL: Input Influence Radius, CTRL+SHIFT: Influence Radius and Stronger Smooth]

Video Tutorial:
https://youtu.be/Ki6I9sRdeUU?t=20m

Name-DE: HB_RoundEdge
Description-DE: Glättet Kantenselektion [SHIFT: Smooth Stronger, CTRL: Input Influence Radius, CTRL+SHIFT: Influence Radius and Stronger Smooth]

ChangeLog:
6/11/2015 Release Version

"""

import c4d
from c4d import utils
from c4d import gui




def SetGlobalPosition(obj, pos):
    m = obj.GetMg()
    m.off = pos
    obj.SetMg(m)

def SetGlobalRotation(obj, rot):
    m = obj.GetMg()
    pos = m.off
    scale = c4d.Vector( m.v1.GetLength(),
                        m.v2.GetLength(),
                        m.v3.GetLength())

    m = utils.HPBToMatrix(rot)

    m.off = pos
    m.v1 = m.v1.GetNormalized()
    m.v2 = m.v2.GetNormalized() 
    m.v3 = m.v3.GetNormalized() 

    obj.SetMg(m)

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:
        doc.AddUndo(c4d.UNDOTYPE_CHANGE, obj)
        obj.InsertUnder(root)
        
    c4d.EventAdd()    
    return



def main():
    doc.StartUndo()
    obj=doc.GetActiveObject()
    objType=obj.GetType()
    ObjPos=obj.GetMg()
    ObjChildren = obj.GetChildren()
   
    RemoveChildren(ObjChildren)
     
    
    SHIFT=False
    CTRL=False
    bc = c4d.BaseContainer()
    c4d.gui.GetInputState(c4d.BFM_INPUT_KEYBOARD,c4d.BFM_INPUT_CHANNEL,bc)

    if bc[c4d.BFM_INPUT_QUALIFIER] ==1 : # SHIFT
        SHIFT=True

    if bc[c4d.BFM_INPUT_QUALIFIER] ==2 : # CTRL
        CTRL=True
        DeformerRadius = gui.InputDialog("Influence Radius")
        if not DeformerRadius: return
    
    if bc[c4d.BFM_INPUT_QUALIFIER] ==3 : #SHIFT & CTRL
        CTRL=True
        SHIFT=True
        DeformerRadius = gui.InputDialog("Influence Radius")
        if not DeformerRadius: return
    
    settings = c4d.BaseContainer()                 # Settings Edge to Spline
    utils.SendModelingCommand(command = c4d.MCOMMAND_EDGE_TO_SPLINE,
                                list = [obj],
                                mode = c4d.MODELINGCOMMANDMODE_EDGESELECTION,
                                bc = settings,
                                doc = doc,
                                flags = c4d.MODELINGCOMMANDFLAGS_CREATEUNDO)
                                
    #doc.AddUndo(c4d.UNDOTYPE_NEW, OriginalSpline)                    
                                
    # NewSpline
    OriginalSpline=obj.GetDown()
    NewSpline=OriginalSpline.GetClone()
    NewSpline.InsertUnder(obj)
    if SHIFT == True:
        RoundPoints=8
        
    else:
        RoundPoints=30
        
        
    
    Roundsettings = c4d.BaseContainer()                 # Settings Edge to Spline
    Roundsettings[c4d.MDATA_SPLINEROUND_POINTS]=RoundPoints
    Roundsettings[c4d.MDATA_SPLINEROUND_TYPE]=3
    utils.SendModelingCommand(command = c4d.ID_MODELING_SPLINE_ROUND_TOOL,
                                list = [NewSpline],
                                mode = c4d.MODELINGCOMMANDMODE_ALL,
                                bc = Roundsettings,
                                doc = doc,
                                flags = c4d.MODELINGCOMMANDFLAGS_CREATEUNDO)
    
  

    # SplineDeformer
    SplineDeformer=c4d.BaseObject(1008982)
    doc.AddUndo(c4d.UNDOTYPE_CHANGE, SplineDeformer)
    SplineDeformer[c4d.SPLINEDEFORMEROBJECT_RADIUS]=0.001
    doc.AddUndo(c4d.UNDOTYPE_CHANGE, SplineDeformer)
    SplineDeformer[c4d.SPLINEDEFORMEROBJECT_USE_LENGTH]=True
    

    
    doc.AddUndo(c4d.UNDOTYPE_CHANGE, SplineDeformer)
    SplineDeformer[c4d.SPLINEDEFORMEROBJECT_ORIGINAL_SPLINE]=OriginalSpline
    doc.AddUndo(c4d.UNDOTYPE_CHANGE, SplineDeformer)
    SplineDeformer[c4d.SPLINEDEFORMEROBJECT_MODIFY_SPLINE]=NewSpline
    
    
    SplineDeformer.InsertAfter(OriginalSpline)
    doc.AddUndo(c4d.UNDOTYPE_NEW, SplineDeformer)
    
    
    if CTRL == True: 
        doc.AddUndo(c4d.UNDOTYPE_CHANGE, SplineDeformer)
        SplineDeformer[c4d.SPLINEDEFORMEROBJECT_RADIUS]=float(DeformerRadius)
        doc.AddUndo(c4d.UNDOTYPE_CHANGE, SplineDeformer)
        SplineDeformer[c4d.SPLINEDEFORMEROBJECT_USE_LENGTH]=True

        
    
    SplineDeformer.Message(c4d.MSG_DESCRIPTION_VALIDATE)
    doc.AddUndo(c4d.UNDOTYPE_CHANGE, SplineDeformer)
    
    
    CSsettings = c4d.BaseContainer()                 
    NewObj=utils.SendModelingCommand(command = c4d.MCOMMAND_CURRENTSTATETOOBJECT,
                                list = [obj],
                                mode = c4d.MODELINGCOMMANDMODE_EDGESELECTION,
                                bc = CSsettings,
                                doc = doc,
                                )
    
    

    NewObj[0].InsertAfter(obj)
    doc.AddUndo(c4d.UNDOTYPE_NEW, NewObj[0])
    
    NewObj[0].SetMg(ObjPos)
    doc.AddUndo(c4d.UNDOTYPE_CHANGE, NewObj[0])
    
    
    
    # New Root is a NULL Object
    if NewObj[0].GetType() == c4d.Onull:
        NewPolyObj=NewObj[0].GetDown()

        
        NewPolyObj.InsertAfter(obj)
        doc.AddUndo(c4d.UNDOTYPE_NEW, NewPolyObj)
        doc.AddUndo(c4d.UNDOTYPE_DELETE,NewObj[0])
        NewObj[0].Remove()
        doc.AddUndo(c4d.UNDOTYPE_CHANGE_SMALL, NewPolyObj)
        doc.SetSelection(NewPolyObj, c4d.SELECTION_ADD)

        InsertChildren(ObjChildren,NewPolyObj)
        doc.AddUndo(c4d.UNDOTYPE_NEW, NewPolyObj)
        NewPolyObj.SetMg(ObjPos)
        doc.AddUndo(c4d.UNDOTYPE_DELETE,obj )
        obj.Remove()
        
    else:# New Root is a PolyObject

        NewObjChildren= NewObj[0].GetChildren()
        
        RemoveChildren(NewObjChildren)
        doc.AddUndo(c4d.UNDOTYPE_CHANGE, NewObj[0])
        doc.SetSelection(NewObj[0], c4d.SELECTION_ADD)
        
        InsertChildren(ObjChildren,NewObj[0])
 
        doc.AddUndo(c4d.UNDOTYPE_DELETE,obj)
        obj.Remove()
        

    
    c4d.EventAdd()
    doc.EndUndo()
    
    
if __name__=='__main__':
    main()
