maya python humanIK retarget

https://github.com/aizwellenstan/maya_hik_retarget_tool
```md
## Script Flow
1. Open New Scene
2. Get Default Hik List
3. Import Source Fbx
4. Rename Fbx with 'source:' namespace
5. Save source hik to list
6. Import Target Fbx
7. Get Target Hik from diff between cuurent hik list and default+source hik list
8. Retarget target Hik to source
9. bake
```

```merge.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
import maya.cmds as cmds
import pymel.core as pm
from maya import mel

def GetHikList():
    mel.eval("HIKCharacterControlsTool;")
    _HUMAN_IK_SOURCE_MENU = "hikSourceList"
    _HUMAN_IK_SOURCE_MENU_OPTION = _HUMAN_IK_SOURCE_MENU + "|OptionMenu"
    items = cmds.optionMenuGrp(_HUMAN_IK_SOURCE_MENU, q=True, ill=True)

    hikList = []
    for i in xrange(0, len(items)):
        label = cmds.menuItem(items[i], q=True, l=True)
        hikList.append(label)

    return hikList

def GetCurrentHikCharacter():
    """
    ....Get the current active character definition.
    ...."""

    mel.eval("HIKCharacterControlsTool;")
    char = mel.eval("hikGetCurrentCharacter();")
    return char

def hikUpdateTool():
    melCode = """
        if ( hikIsCharacterizationToolUICmdPluginLoaded() )
        {
            hikUpdateCharacterList();
            hikUpdateCurrentCharacterFromUI();
            hikUpdateContextualUI();
            hikControlRigSelectionChangedCallback;
            hikUpdateSourceList();
            hikUpdateCurrentSourceFromUI();
            hikUpdateContextualUI();
            hikControlRigSelectionChangedCallback;
        }
        """
    try:
        mel.eval(melCode)
    except:
        pass

def SetHikChar(targetChar):
    mel.eval("HIKCharacterControlsTool;")
    mel.eval('hikSetCurrentCharacter("{0}")'.format(targetChar))
    hikUpdateTool()

def SetHikSourceChar(source):
    _HUMAN_IK_SOURCE_MENU = "hikSourceList"
    _HUMAN_IK_SOURCE_MENU_OPTION = _HUMAN_IK_SOURCE_MENU + "|OptionMenu"
    items = cmds.optionMenuGrp(_HUMAN_IK_SOURCE_MENU, q=True, ill=True)
    for i in xrange(0, len(items)):
        label = cmds.menuItem(items[i], q=True, l=True)

        # 空白が頭に入っているので除去
        if label.lstrip() == source:
            cmds.optionMenu(_HUMAN_IK_SOURCE_MENU_OPTION, e=True, sl=i + 1)
            mel.eval("hikUpdateCurrentSourceFromUI()")
            mel.eval("hikUpdateContextualUI()")
            mel.eval("hikControlRigSelectionChangedCallback")
            break

def isCharacterDefinition(char):
	# Check Node Exists
	if not cmds.objExists(char): return False
	
	# Check Node Type
	if cmds.objectType(char) != 'HIKCharacterNode': return False
	
	return True

def getCharacterNodes(char):
    # Check Node
    if not isCharacterDefinition(char):
        raise Exception(
            'Invalid character definition node! Object "'
            + char
            + '" does not exist or is not a valid HIKCharacterNode!'
        )

    # Get Character Nodes
    charNodes = mel.eval('hikGetSkeletonNodes "' + char + '"')

    # Return Result
    return charNodes

def bake(char, start, end):
    cmds.playbackOptions(min=start, max=end)

    bones = getCharacterNodes(char)

    # Bake Animation
    cmds.bakeResults(
        bones,
        simulation=True,
        t=(start, end),
        sampleBy=1,
        disableImplicitControl=True,
        preserveOutsideKeys=False,
        sparseAnimCurveBake=False,
        removeBakedAttributeFromLayer=False,
        bakeOnOverrideLayer=False,
        minimizeRotation=False,
        at=["tx", "ty", "tz", "rx", "ry", "rz"],
    )

def main(sourceFile, targetFile):
    cmds.file(new=True, force=True)
    defaultHikList = GetHikList()
    cmds.file(sourceFile, i=True, force=True)
    allTransform = cmds.ls()
    cmds.select(allTransform)
    for i in allTransform:
        try:
            oldName = i.split("|")[-1]
            newName = ":source:{}".format(oldName)
            if ":" in oldName:
                newName = ":source:" + oldName.split(":")[-1]
            new = cmds.rename(oldName, newName)
        except:
            continue

    joints = cmds.ls("*:*", long=True, type="joint")
    cmds.select(joints)
    all_keys = sorted(cmds.keyframe(joints, q=True) or [])
    if all_keys:
        start = int(all_keys[0])
        end = int(all_keys[-1])
    print(start, end)

    sourceChar = GetCurrentHikCharacter()

    cmds.file(targetFile, i=True, force=True)

    hikList = GetHikList()

    targetChar = ""
    for hik in hikList:
        if hik not in defaultHikList:
            if hik != sourceChar:
                targetChar = hik.lstrip()
                break

    SetHikChar(targetChar)

    SetHikSourceChar(sourceChar)

    bake(targetChar, start, end)
```

```merge_ui.py
#-*- coding:utf-8
VERSION = 'v1'

import ConfigParser
import csv
import glob
import os
import re
import sys
import maya
import pymel.core as pm

sys.path.append(r'J:/vd2/tool/runtime/qbLauncherX/versions/002.009.000/lib/all/Qt.py/python')
from Qt import __binding__, QtGui, QtCore, QtWidgets
if __binding__ == 'PySide2':
    import pyside2uic as pysideuic
    from shiboken2 import wrapInstance
elif __binding__ == 'PySide':
    import pysideuic
    from shiboken import wrapInstance

import maya.OpenMayaUI as apiUI

def getMainWindow():
    pointer = apiUI.MQtUtil.mainWindow()
    if pointer is not None:
        _MainWindow = wrapInstance(long(pointer), QtWidgets.QWidget)
    return _MainWindow

#####################UI########################
class Main_Window(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(Main_Window, self).__init__(parent)
        self.inint_widget()

    def selectFile(self, ftype):
        if self.sourcefname is not None and os.path.isfile(self.sourcefname):
            directory = self.sourcefname
        else:
            directory = QtCore.QDir.currentPath()
        dialog = QtWidgets.QFileDialog.getOpenFileName(
            self, 'Select fbx file', directory,  'fbx files (*fbx)')
        if dialog[0] != 0:
            if ftype == 'source':
                self.sourcefname = str(dialog[0])
                self.sourceflineEdit.setText(str(dialog[0]))
            else:
                self.targetfname = str(dialog[0])
                self.targetflineEdit.setText(str(dialog[0]))

    def run(self, sourceFile, targetFile):
        sys.path.append(r"I:/script/bin/td/maya/scripts/mocapConvert/merge")
        import merge
        reload(merge)
        print(sourceFile, targetFile)
        merge.main(sourceFile, targetFile)

    def inint_widget(self):
        QV_0_ayout   = QtWidgets.QVBoxLayout()
        QV_A_ayout   = QtWidgets.QHBoxLayout()       
        QV_B_ayout   = QtWidgets.QHBoxLayout()
        QV_C_ayout   = QtWidgets.QVBoxLayout()
        QV_D_ayout   = QtWidgets.QHBoxLayout()
        QV_E_ayout   = QtWidgets.QHBoxLayout()

        self.sourcefname = ''
        self.sourceflineEdit = QtWidgets.QLineEdit()
        label = QtWidgets.QLabel('Source:       ')
        QV_A_ayout.addWidget(label)
        QV_A_ayout.addWidget(self.sourceflineEdit)
        sourceBrouseBtn = QtWidgets.QPushButton('...')
        QV_A_ayout.addWidget(sourceBrouseBtn)
        sourceBrouseBtn.clicked.connect(lambda: self.selectFile('source'))

        self.targetfname = ''
        self.targetflineEdit = QtWidgets.QLineEdit()
        label = QtWidgets.QLabel('Target:       ')
        QV_B_ayout.addWidget(label)
        QV_B_ayout.addWidget(self.targetflineEdit)
        targetBrouseBtn = QtWidgets.QPushButton('...')
        QV_B_ayout.addWidget(targetBrouseBtn)
        targetBrouseBtn.clicked.connect(lambda: self.selectFile('target'))

        QV_0_ayout.addLayout(QV_D_ayout)
        QV_0_ayout.addLayout(QV_E_ayout)
        QV_0_ayout.addLayout(QV_A_ayout)
        QV_0_ayout.addLayout(QV_B_ayout)

        # self.seqListTextField = QtWidgets.QLineEdit()
        # self.seqListTextField.setFixedHeight(20)
        # self.seqListTextField.setPlaceholderText('Enter Seq Seperate With Comma')
        # self.seqListTextField.setToolTip('s026, s027')
        # self.seqListTextField.setObjectName('testLineEdit')

        button_layout = QtWidgets.QLabel(' ')
        runBtn = QtWidgets.QPushButton('Transfer')
        QV_C_ayout.addWidget(runBtn)
        runBtn.clicked.connect(lambda: self.run(self.sourcefname, self.targetfname))
        # shotgun_button = QtWidgets.QPushButton('OPEN_SHOTGUN')
        # QV_C_ayout.addWidget(self.seqListTextField)
        # QV_C_ayout.addWidget(shotgun_button)
        # shotgun_button.setStyleSheet("background-color: orange")
        
        QVlayout = QtWidgets.QVBoxLayout()    
        QVlayout.addLayout(QV_0_ayout)
        QVlayout.addLayout(QV_C_ayout)

        w = QtWidgets.QWidget()
        w.setLayout(QVlayout)
        self.setCentralWidget(w)
        self.setWindowTitle('Animation Retarget Tool')
        print("INIT")

########################################################

def run():
    global main_window
    try:
        main_window.close()
    except:
        pass
    maya_main_wid = getMainWindow()
    main_window = Main_Window(parent = maya_main_wid)
    main_window.show()
    main_window.setMinimumSize(600,250)
    main_window.setMaximumSize(600,250)

if __name__ == '__main__':
    run()
```