splinecraft
1/2/2017 - 2:39 AM

glitchfinder_v2

glitchfinder_v2

from pymel.core import *
import pymel.core as pm
import json
from collections import Counter

"""

Glitch finder version 1.0 by Eric Luhta, ericl@splinecraft.com

Creatist: Eric Luhta
ericl@splinecraft.com
www.splinecraft.com

Glitchfinder is designed to help in animating cycles that use pre and post infinity curves that are offset from each other. Throughout editing this type of animation, it is inevitable that some curves will have their lengths altered from the core cycle length, creating glitches in the motion. It is also possible that the start and end values of the curves can become changed, and once the animation is past blocking, it can be time consuming to track down these tiny little annoyances through many curves. Glitchfinder will make that process much more efficient and simpler.

TO USE: Select controls and click the button.

Glitchfinder will go through all selected controls' curves and find the most common length among them. It will then sort all of the curve names into 3 lists:

1.  The common curve length (it will also include curves that are half or double the common length since these lengths are commonly used in cycles and won't create glitches due to length.)

2.  The uncommon curve lengths

3.  Curves that do not have the same value on the start and end keys.

Armed with that useful information, go forth and conquer.

NOTE: If by chance there are the same number of common and uncommon length curves, they will be divided equally between the two categories, as there is no way for the tool to know which one is correct.

TO INSTALL:

put glitchfinder.py in your prefs > scripts folder
put glitchfinder_header.png and glitchfinder-icon.png in your prefs > icons folder

to run use python command:

import glitchfinder
reload(glitchfinder)

"""


def get_curve_length(curve):
    # returns the frame length of a curve

    first = pm.findKeyframe(curve, which='first')
    last = pm.findKeyframe(curve, which='last')
    return abs(first - last)


def compare_start_end_values(curve):
    # looks at the start and end values of a curve and returns if they match or not

    first = pm.findKeyframe(curve, which='first')
    last = pm.findKeyframe(curve, which='last')
    firstVal = pm.keyframe(curve, q=True, time=(first, first), vc=True)
    lastVal = pm.keyframe(curve, q=True, time=(last, last), vc=True)
    return firstVal == lastVal


def find_glitch():
    curvelist = pm.keyframe(q=True, sl=True, name=True)

    if len(curvelist) > 0:
        curve_lengths = {}
        mismatched_start_end = {}

        # build the dictionary of curve lengths for each curve
        for curve in curvelist:
            curve_lengths[curve] = get_curve_length(curve)

        for curve in curvelist:
            mismatched_start_end[curve] = compare_start_end_values(curve)

        # put values into a list to work with Counter
        # count occurances of each different curve length
        counted = list(curve_lengths.values())
        c = Counter(counted)

        # get rid of 0 and 1 frame curves in list
        del c[0.0], c[1.0]

        isolate_most_common = c.most_common(1)
        isolate_most_common = list(*isolate_most_common)

        most_common = isolate_most_common[0]

        # make 2 lists, one for most common curves by length, the other for the rest
        common_lengths = {}
        uncommon_lengths = {}
        mismatched_values = []

        # iterate through dictionary to place into appropriate lists
        for key, value in curve_lengths.iteritems():
            if value == most_common or value == most_common * 2 or value == most_common / 2:
                common_lengths[str(key)] = value
            elif value > 1:
                uncommon_lengths[str(key)] = value

        for key, value in mismatched_start_end.iteritems():
            if value == False:
                mismatched_values.append(str(key))

        # output
        output1 = json.dumps(common_lengths, sort_keys=True, indent=4, separators=(',', ':  '))

        # if no uncommon curves found, make it clear
        if len(uncommon_lengths) == 0:
            output2 = "No curves outside common length found."
        else:
            output2 = json.dumps(uncommon_lengths, sort_keys=True, indent=4, separators=(',', ':  '))

        # mismatched start and end value list
        if len(mismatched_values) == 0:
            output3 = "No curves with mismatched start and end values."
        else:
            output3 = json.dumps(mismatched_values, indent=4, separators=(',', ':  '))

        w.common_text.setText(output1)
        w.uncommon_text.setText(output2)
        w.mismatched_text.setText(output3)

    else:
        pm.warning('[glitchfinder.py]: Please select some animation curves'),


######
# Output window stuff
class Window_UI:
    def __init__(self):
        if pm.window('fixtheglitch', exists=True):
            pm.deleteUI('fixtheglitch')
        self.window_id = 'fixtheglitch'

    def build_ui(self):
        outputWindow = pm.window(self.window_id, title='glitchfinder', width=385, height=600, mnb=True, mxb=True, sizeable=True)

        mainLayout = pm.columnLayout(w=385, h=400)

        imagePath = pm.internalVar(upd=True) + "icons/glitchfinder_header.png"
        pm.image(w=400, h=75, image=imagePath)
        pm.text(' ')
        pm.text(label='Select curves, then:', align='center')
        pm.button(label='Find Glitches', w=400, bgc=(.905, .803, .231), command=pm.Callback(find_glitch))

        form = pm.formLayout()
        tabs = pm.tabLayout(innerMarginWidth=5, innerMarginHeight=5, w=385, h=400)
        pm.formLayout(form, edit=True,
                      attachForm=((tabs, 'top', 0), (tabs, 'left', 0), (tabs, 'bottom', 0), (tabs, 'right', 0)))

        # Main tool tab
        child1 = pm.rowColumnLayout(numberOfColumns=1, columnWidth=(1, 385))
        self.uncommon_text = pm.scrollField(editable=False, wordWrap=False, width=385, height=400)
        pm.setParent('..')

        child2 = pm.rowColumnLayout(numberOfColumns=1, columnWidth=(1, 385))
        self.common_text = pm.scrollField(editable=False, wordWrap=False, width=385, height=400)
        pm.setParent('..')

        child3 = pm.rowColumnLayout(numberOfColumns=1, columnWidth=(1, 385))
        self.mismatched_text = pm.scrollField(editable=False, wordWrap=False, width=385, height=400)
        pm.setParent('..')

        child4 = pm.rowColumnLayout(numberOfColumns=1, columnWidth=(1, 385))
        aboutText = ""
        aboutText += "Creatist: Eric Luhta\n"
        aboutText += "ericl@splinecraft.com\n"
        aboutText += "www.splinecraft.com\n"
        aboutText += "\n"
        aboutText += "Glitchfinder is designed to help in animating cycles that use pre and post infinity curves that are offset from each other. Throughout editing this type of animation, it is inevitable that some curves will have their lengths altered from the core cycle length, creating glitches in the motion. It is also possible that the start and end values of the curves can become changed, and once the animation is past blocking, it can be time consuming to track down these tiny little annoyances through many curves. Glitchfinder will make that process much more efficient and simpler.\n"
        aboutText += "\n"
        aboutText += "TO USE: Select all animation curves and click the button.\n"
        aboutText += "\n"
        aboutText += "Glitchfinder will go through all selected curves and find the most common length among them. It will then sort all of the curve names into 3 lists:\n"
        aboutText += "\n"
        aboutText += "1.  The common curve length (it will also include curves that are half or double the common length since these lengths are commonly used in cycles and won't create glitches due to length.)\n"
        aboutText += "\n"
        aboutText += "2.  The uncommon curve lengths\n"
        aboutText += "\n"
        aboutText += "3.  Curves that do not have the same value on the start and end keys.\n"
        aboutText += "\n"
        aboutText += "Armed with that useful information, go forth and conquer.\n"
        aboutText += "\n"
        aboutText += "NOTE: If by chance there are the same number of common and uncommon length curves, they will be divided equally between the two categories, as there is no way for the tool to know which one is correct.\n"
        pm.scrollField(editable=False, wordWrap=True, w=385, h=400, text=aboutText)
        pm.setParent('..')

        # Tabs
        pm.tabLayout(tabs, edit=True,
                     tabLabel=((child1, 'Uncommon'), (child2, 'Common'), (child3, 'Mismatched'), (child4, 'About')))
        pm.showWindow(outputWindow)

# Let's see if this code is worth the price we paid for it.
w = Window_UI()
w.build_ui()