Get the Neighboring Keys from a Selected Key?
-
Hi,
Is there a way to get the neighboring key from a selected key?
My end goal is to set the key tangent of a selected key.
Apparently, the value to be set is not in percentage but in actual value relative to the neighboring keys. Hence the question.Is this possible?
-
Hello @bentraje,
thank you for reaching out to us. I am not quite sure how your (main) question is meant. You usually iterate over keys using an index via CCurve.GetKeyCount(). So the neighboring keys would be
i - 1
andi + 1
plus some clamping so that you do not exceed the index boundaries. BecauseCKey
is aGeListNode
, you can also iterate through the list head withGeListNode.GetNext
and so on. But I am not sure if keys are always temporally ordered under their list head (my hunch would be that they are not always temporally ordered).About your second question, yes, tangents are not expressed as percent values just as they are not in the Attribute Manager.
When you have a key or tangent, you can form a point out of their time and value components, so that you can compute things using algebraic expressions.
# Two keys in a document. keyA: c4d.CKey keyB: c4d.CKey # Computing values interpreting keys as 2D vectors. We construct (time, value) vectors for key # A and B and then compute the mean value, i.e., the point lying on the mid point of the segment # which is connecting the two keys. p: c4d.Vector = c4d.Vector(keyA.GetTime().Get(), keyA.GetValue(), 0) q: c4d.Vector = c4d.Vector(keyA.GetTime().Get(), keyA.GetValue(), 0) mid_vec: c4d.Vector = c4d.utils.MixVec(p, q, .5) mid_time: c4d.BaseTime = c4d.BaseTime(mid.x) mid_value: float = mid.y # We could of course also do things manually, for example when we want to only operate on one axis. # Here we compute 50% time mark between #keyA and #keyB. mid_time_2: c4d.BaseTime = c4d.BaseTime( c4d.utils.MixValue(keyA.GetTime().Get(), keyB.GetTime().Get(), .5) )
But in general, I would advise against messing too much which tangents in a completely free manner, and instead rather rely on the presets. Good tangent behavior in a timeline can be tricky, as there are often special cases where you want things to behave differently. There is a reason why the tangent preset is not 'custom' by default.
Cheers,
Ferdinand -
Hi @ferdinand
Thanks for the response:
Basically, in your script:
keyA and keyB is already declared.In my case, I only want keyB declared (as it is being detected). and have a script determine the neighbor key (which is keyA).
Is that possible?I just need the neighboring keys so I can normalize the tangents to a 0 to 1 value.
For reference, houdini has set its tangent in 0 to 1 (or in percentage) so it can easily modified.
-
Hey @bentraje,
In my case, I only want keyB declared (as it is being detected). and have a script determine the neighbor key (which is keyA). Is that possible?
You should show me how you access that key. I lined out the two methods how to access neighboring keys. When you have no index for the key, you can either live dangerously and just assume that
myKey.GetPred
will return the temporally previous key or sort them yourself.import c4d op: c4d.BaseObject | None # The primary selected object in `doc`. Can be `None`. def main() -> None: """Called by Cinema 4D when the script is being executed. """ if not op: return track: c4d.CTrack | None = op.GetFirstCTrack() if not track: return curve: c4d.CCurve = track.GetCurve() if (curve.GetKeyCount() < 1): return key: c4d.CKey = curve.GetKey(0) while (key): print (key, key.GetTime().Get()) key = key.GetNext() if __name__ == '__main__': main()
I ran this on an object with a track where I deliberately did not created the keys in temporal order, and the output is sorted. I would however not bet on the fact that all track types will behave like this.
<c4d.CKey object at 0x0000017AB3612640> 0.0 <c4d.CKey object at 0x0000017AB3612B40> 0.26666666666666666 <c4d.CKey object at 0x0000017AB36123C0> 0.7666666666666667 <c4d.CKey object at 0x0000017AB3612840> 1.2666666666666666 <c4d.CKey object at 0x0000017AB36128C0> 2.433333333333333 <c4d.CKey object at 0x0000017AB36126C0> 3.0
I just need the neighboring keys so I can normalize the tangents to a 0 to 1 value. For reference, houdini has set its tangent in 0 to 1 (or in percentage) so it can easily modified.
Without wanting to be rude, I just showed you above how to operate with percentage values in Cinema 4D. Tangents in Cinema 4D are not normalized and operate in object space. The timeline is there no exception and I cannot change that for you.
Cheers,
Ferdinand -
Hi @ferdinand
Apologies for the late response.
RE: You should show me how you access that key.
My bad. But it's on the previous thread you answered by manually selecting a keyframe and storign it in a variable.
https://developers.maxon.net/forum/topic/15344/get-selected-keyframes/3RE: I just showed you above how to operate with percentage values in Cinema 4D.
My bad. I missed it. I was looking immediately at the declaration.keyA: c4d.CKey keyB: c4d.CKey
which I only want one key to be declared.
===
In summary, the GetNext() and GetPred() solved the problem in getting the Neighboring Keys from a Selected Key.