// rd_AverageTrackers.jsx // Copyright (c) 2007-2013 redefinery (Jeffrey R. Almasol). All rights reserved. // check it: www.redefinery.com // // Name: rd_AverageTrackers // Version: 2.0 // // Description: // This script creates a null layer whose position is an // expression-driven value of the average of the selected // layer's motion tracker track points of your choosing. // A dialog box lists the track points on the layer, with the // enabled ones selected by default. // // Note: This script requires After Effects CS4 or later. // // Originally requested by Stu Maschwitz. // // Legal stuff: // This script is provided "as is," without warranty of any kind, expressed // or implied. In no event shall the author be held liable for any damages // arising in any way from the use of this script. // // In other words, I'm just trying to share knowledge with and help out my // fellow AE script heads, so don't blame me if my code doesn't rate. :-) // rd_AverageTrackers() // // Description: // This function contains the main logic for this script. // // Parameters: // thisObj - "this" object. // // Returns: // Nothing. // (function rd_AverageTrackers(thisObj) { // Globals var onWindows = ($.os.indexOf("Windows") !== -1); var rd_AverageTrackersData = new Object(); // Store globals in an object rd_AverageTrackersData.scriptName = "rd: Average Trackers"; rd_AverageTrackersData.scriptTitle = rd_AverageTrackersData.scriptName + " v2.0"; rd_AverageTrackersData.strHeading = {en: "Select track points to average:"}; rd_AverageTrackersData.strCaption = (onWindows) ? {en: "(Ctrl-click to select multiple track points)"} : {en: "(Cmd-click to select multiple track points)"}; rd_AverageTrackersData.strOK = {en: "OK"}; rd_AverageTrackersData.strCancel = {en: "Cancel"}; rd_AverageTrackersData.strHelp = {en: "?"}; rd_AverageTrackersData.strMinAE90 = {en: "This script requires Adobe After Effects CS4 or later."}; rd_AverageTrackersData.strErrNoCompSel = {en: "Cannot perform operation. Please select or open a single composition in the Project panel, and try again."}; rd_AverageTrackersData.strNoSelLayer = {en: "Cannot perform operation. Please select a single layer with at least two motion tracker track points, and try again."}; rd_AverageTrackersData.strHelpText = { en: "Copyright (c) 2007-2013 redefinery (Jeffrey R. Almasol). All rights reserved.\n" + "\n" + "This script creates a null layer whose position is an expression-driven value of the average of the selected layer's motion tracker track points of your choosing. A dialog box lists the track points on the layer, with the enabled ones selected by default.\n" + "\n" + "Note: This script requires After Effects CS4 or later.\n" + "\n" + "Originally requested by Stu Maschwitz.\n" }; // rd_AverageTrackers_localize() // // Description: // This function localizes the given string variable based on the current locale. // // Parameters: // strVar - The string variable's name. // // Returns: // String. // function rd_AverageTrackers_localize(strVar) { return strVar["en"]; } // rd_AverageTrackers_buildUI() // // Description: // This function builds the user interface. // // Parameters: // thisObj - Panel object (if script is launched from Window menu); null otherwise. // // Returns: // Window or Panel object representing the built user interface. // function rd_AverageTrackers_buildUI(thisObj) { var pal = new Window("dialog", rd_AverageTrackersData.scriptName, undefined, {resizeable:true}); if (pal !== null) { var res = """group { orientation:'column', alignment:['fill','fill'], heading: StaticText { text:'""" + rd_AverageTrackers_localize(rd_AverageTrackersData.strHeading) + """', alignment:['fill','top'] }, lst: ListBox { alignment:['fill','fill'], properties:{ multiselect:true } }, cap: StaticText { text:'""" + rd_AverageTrackers_localize(rd_AverageTrackersData.strCaption) + """', alignment:['fill','bottom'] }, cmds: Group { alignment:['fill','bottom'], help: Button { text:'""" + rd_AverageTrackers_localize(rd_AverageTrackersData.strHelp) + """', maximumSize:[30,20], alignment:['left','bottom'] }, """; if (onWindows) res += """ okBtn: Button { text:'""" + rd_AverageTrackers_localize(rd_AverageTrackersData.strOK) + """', alignment:['right','bottom'], preferredSize:[-1,20] }, cancelBtn: Button { text:'""" + rd_AverageTrackers_localize(rd_AverageTrackersData.strCancel) + """', alignment:['right','bottom'], preferredSize:[-1,20] }, """; else res += """ cancelBtn: Button { text:'""" + rd_AverageTrackers_localize(rd_AverageTrackersData.strCancel) + """', alignment:['right','bottom'], preferredSize:[-1,20] }, okBtn: Button { text:'""" + rd_AverageTrackers_localize(rd_AverageTrackersData.strOK) + """', alignment:['right','bottom'], preferredSize:[-1,20] }, """; res += """ }, }"""; pal.grp = pal.add(res); pal.grp.cmds.margins.top = 5; pal.grp.lst.preferredSize.height = 100; pal.layout.layout(true); pal.grp.minimumSize = pal.grp.size; pal.layout.resize(); pal.onResizing = pal.onResize = function () {this.layout.resize();} pal.grp.cmds.help.onClick = function () {alert(rd_AverageTrackersData.scriptTitle + "\n" + rd_AverageTrackers_localize(rd_AverageTrackersData.strHelpText), rd_AverageTrackersData.scriptName);} pal.grp.cmds.okBtn.onClick = rd_AverageTrackers_doIt; } return pal; } // rd_AverageTrackers_getMTTrackPoints() // // Description: // This function retrieves the motion tracker track points on the specified layer. // // Parameters: // layer - The layer to check. // // Returns: // Array of motion tracker track points // function rd_AverageTrackers_getMTTrackPoints(layer) { var mtPts = new Array(); if (layer !== null) { var mtGroup = layer("ADBE MTrackers"); if (mtGroup !== null) { var mtracker; for (var i=1; i<=mtGroup.numProperties; i++) { mtracker = mtGroup.property(i); for (var j=1; j<=mtracker.numProperties; j++) mtPts[mtPts.length] = mtracker.property(j); } } } return mtPts; } // rd_AverageTrackers_doIt() // // Description: // This callback function performs the main operation. // // Parameters: // None. // // Returns: // Nothing // function rd_AverageTrackers_doIt() { var selection = this.parent.parent.lst.selection; app.beginUndoGroup(rd_AverageTrackersData.scriptName); var comp = app.project.activeItem; var layer = comp.selectedLayers[0]; var nullLayer = comp.layers.addNull(); nullLayer.name = "Average"; var mt; var expr = "l = thisComp.layer(\"" + layer.name + "\");\n("; for (var i=0; i 0) expr += " + "; expr += "l.motionTracker(\"" + mt.parentProperty.name + "\")(\"" + mt.name + "\").attachPoint+l.motionTracker(\"" + mt.parentProperty.name + "\")(\"" + mt.name + "\").attachPointOffset"; } expr += ") / " + selection.length + ";"; nullLayer.position.expression = expr; nullLayer.position.expressionEnabled = true; app.endUndoGroup(); this.parent.parent.parent.close(); } // main code: // // Prerequisites check if (parseFloat(app.version) < 9.0) alert(rd_AverageTrackers_localize(rd_AverageTrackersData.strMinAE90), rd_AverageTrackersData.scriptName); else { // Make sure only a single comp is selected if (app.project === null) return; // Get the current (active/frontmost) comp var comp = app.project.activeItem; if ((comp === null) || !(comp instanceof CompItem)) { alert(rd_AverageTrackers_localize(rd_AverageTrackersData.strErrNoCompSel), rd_AverageTrackersData.scriptName); return; } // Make sure there is a selected layer with at least two motion tracker track points if (comp.selectedLayers.length !== 1) { alert(rd_AverageTrackers_localize(rd_AverageTrackersData.strNoSelLayer), rd_AverageTrackersData.scriptName); return; } var layer = comp.selectedLayers[0]; rd_AverageTrackersData.mtPts = rd_AverageTrackers_getMTTrackPoints(layer); if (rd_AverageTrackersData.mtPts.length < 2) { alert(rd_AverageTrackers_localize(rd_AverageTrackersData.strNoSelLayer), rd_AverageTrackersData.scriptName); return; } var dlg = rd_AverageTrackers_buildUI(thisObj); if (dlg !== null) { // Add the list of motion tracker track points to the UI for (var i=0; i " + rd_AverageTrackersData.mtPts[i].name); if (rd_AverageTrackersData.mtPts[i].enabled) dlg.grp.lst.items[i].selected = true; } // Show the dialog dlg.center(); dlg.show(); } } })(this);