ADOBE AFTER EFFECTS: Forum Expressions Tutorials Creative Cloud

remove keys on property A except where property B has keys

COW Forums : Adobe After Effects Expressions

<< PREVIOUS   •   FAQ   •   VIEW ALL   •   PRINT   •   NEXT >>
Steve Sierra
remove keys on property A except where property B has keys
on Apr 7, 2017 at 1:08:54 pm

Hello,

I am new to this forum and to scripting, so nice to meet you and sorry for my "noobism"
For my first script, I am trying to delete all keys from property A (which has keys on every frame), except where property B has keys (not necissarely on every frame).
My strategy :
1. get times of BProp keys
2. delete keys on AProp except at times retrieved in 1.

I think step 1 is OK, I followed a tutorial and can see that the function returns the correct times.
Things get wierd in step 2. I've tweaked all parts of the code and got all kinds of results, including the exact opposite of what I want (delete Akeys at Btimes), but can't get it to work correctly... Might be a mixup of key indexes/ comp frame time, or a problem with the nested for loops...

Here's a basic version of the setup... Doesn't work at all, but shows the strategy.

Any help appreciated !
Thanks ;)

// create an undo group
app.beginUndoGroup("S_RemoveKeys");


var AProp = app.project.item(1).layer("Shape Layer 1").property("Contents").property("Group 1").property("Contents").property("Path 1").property("Path");
var BProp = app.project.item(1).layer("KeyLayer Comp 1").property("Time Remap");

var BKeyTimes = getKeyTimes(BProp);
var ALen = AProp.numKeys;
var FramesTime = ALen-1
var BLen = BProp.numKeys;
CurItem.layers.addText(FramesTime.toString());


for (var t = FramesTime; t>0; --t) { // for t = every frame (= Akeys index - 1)
var e = t+1; // e = AKey index at time "t"
for(var i = BLen; i>=0;--i) { // for i = every index of "BKeyTimes" Array
if (t = BKeyTimes[i]) { // check if "t" is in "BKeyTimes" Array
}else{
AProp.removeKey(e); // if "t" is not in "BKeyTimes" Array, delete key
}
}
}


function getKeyTimes(prop) {
var KeyTimes = new Array();
var KeysLen = prop.numKeys;

for(var k =1; k&lt;=KeysLen; k++) { // for k = every key index
var q = prop.keyTime(k)*25 // get "prop" key times, multiply by framerate(25) to get times in frames
KeyTimes.push(q); // add to "KeyTimes" Array
}
return KeyTimes;
}


// close the undo group
app.endUndoGroup();


Return to posts index

Xavier Gomez
Re: remove keys on property A except where property B has keys
on Apr 9, 2017 at 10:58:28 am

There is a misprint inside the secondary loop, it should be: if (t == BKeyTimes[i]) { (==, not =).

Additionnaly, the loop logic isnt very good: as it is now, it will remove a keyframe on A as soon as that keyframe's time doesnt match ALL keyframes times on B, which is impossible except in rare situations (only one key on B).
You'd rather want to keep the key on A if its time matches ONE key time on B, and remove otherwise.

Here is another approach, simpler to write down, but which might be slow if many keyframes, because of the use of nearestKeyIndex:

function sameTimes(t1, t2){
return Math.abs(t2-t1)<;=0.0005;
};
function removeAllKeys(prop){
while(prop.numKeys>0) prop.removeKey(prop.numKeys);
};

function removeKeys(A, B){
if (B.numKeys===0) return removeAllKeys(A);
var idxA, idxB, tA, tB;
for (idxA=A.numKeys; idxA>0; idxA--){
tA = A.keyTime(idxA);
idxB = B.nearestKeyIndex(tB);
tB = B.keyTime(idxB);
if (!sameTimes(tA, tB)) A.removeKey(idxA);
};
};


Xavier


Return to posts index

Steve Sierra
Re: remove keys on property A except where property B has keys
on Apr 11, 2017 at 8:18:34 am

Hello Xavier,

Thanks for your reply !
I haven't had the time to thourougly check out your proposition, but I can't seem to get it to work...
I believe there was a ";" too many in the first function, but I think there might be a problem with the last function as well.
Can IdxB use tB to define itself while tB uses idxB ? Doesn't one have to be defined first to define the second ?

Thanks again for your answer, I'll fiddle with it tomorrow and keep you posted !

Cheers !;)


Return to posts index


Xavier Gomez
Re: remove keys on property A except where property B has keys
on Apr 11, 2017 at 10:24:26 am

Yes you're right for both.
The ";" come from the auto-formatting from the browser (i tried to fix but failed).
And idxB = B.nearestKeyIndex(tB); should indeed be:

idxB = B.nearestKeyIndex(tA);

I havent tried to check whether it works or not. It should, be can be slow if many keyframes.
Your way, collecting keyframes first and compare afterwards, should be faster in that case.

Xavier


Return to posts index

Steve Sierra
Re: remove keys on property A except where property B has keys
on Apr 11, 2017 at 1:37:26 pm

Yep ! That works Xavier 😉 Thank you very much...

Meanwhile, I did a less elegant version of my own... It has more functions, but doeasn't use nearestKeyIndex.
Could you tell me which one is quickest ?

Thanks again !
S.

PS: There seems to be an error in the pasted code in the first function... it's : for(var t = 1; t <= Len; t++)

var B = app.project.item(1).layer("KeyLayer Comp 1").property("Time Remap");
var A= app.project.item(1).layer("Shape Layer 1").property("Contents").property("Group 1").property("Contents").property("Path 1").property("Path");
var ATimes = [];
var BTimes = [];
var BAIndexes = [];

//--------------------------------------------------------------------------------------------------------------------------
app.beginUndoGroup("S_RemoveKeys");
//--------------------------------------------------------------------------------------------------------------------------

BTimes = getKeyTimes(B);
ATimes = getKeyTimes(A);
removePostKeys(A, B, ATimes, BTimes);
removeMiddleKeys(A, B, ATimes, BTimes);
removePreKeys(A, ATimes, BTimes);

//--------------------------------------------------------------------------------------------------------------------------
app.endUndoGroup();
//--------------------------------------------------------------------------------------------------------------------------

function getKeyTimes(prop){
var Len = prop.numKeys;
var keyTimes = [];
for(var t = 1; t &lt;= Len; t++){
var e = prop.keyTime(t);
keyTimes.push(e);
}
return keyTimes;
}
function removePostKeys(A, B, ATimes, BTimes){
for(var i = B.numKeys - 1; i > 0; i--){
var c = BTimes[i];
for(var t = A.numKeys; t > 0; t--){
var a = ATimes[t-1];
if(a !== c ){
A.removeKey(t);
}else{
break;
}
}break;
}
}

function removeMiddleKeys(A, B, ATimes, BTimes){
for(var j = B.numKeys - 1; j > 0; j--){
for(var i = j; i > 0; i--){
var c = BTimes[i];
var q = BTimes[i - 1];
for(var t = A.numKeys - 1; t > 0; t--){
var a = ATimes[t];
if(a > q && a &lt; c ){
A.removeKey(t + 1);
}else{
if(a == q){
break;
}
}
}
}break;
}
}
function removePreKeys(A, ATimes, BTimes){
var c = BTimes[1];
for(var t = A.numKeys; t > 0; t--){
var a = ATimes[t];
if(a &lt; c ){
A.removeKey(t);
}
}
}


Return to posts index

Steve Sierra
Re: remove keys on property A except where property B has keys
on Apr 11, 2017 at 1:50:22 pm

Hello again,

Could someone tell me how to mark a post as resolved ?
Thanks !


Return to posts index

<< PREVIOUS   •   VIEW ALL   •   PRINT   •   NEXT >>
© 2017 CreativeCOW.net All Rights Reserved
[TOP]