Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Get the Neighboring Keys from a Selected Key?

    Cinema 4D SDK
    2024 2023 python
    2
    5
    786
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • B
      bentraje
      last edited by

      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?

      c7daf8e1-ce81-4ea4-8647-ed828b71398a-image.png

      ferdinandF 1 Reply Last reply Reply Quote 0
      • ferdinandF
        ferdinand @bentraje
        last edited by ferdinand

        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 and i + 1 plus some clamping so that you do not exceed the index boundaries. Because CKey is a GeListNode, you can also iterate through the list head with GeListNode.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.
        54171db1-fe31-46ba-b2a0-4b29ae8a8fd7-image.png

        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

        MAXON SDK Specialist
        developers.maxon.net

        1 Reply Last reply Reply Quote 0
        • B
          bentraje
          last edited by

          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.

          image.png

          ferdinandF 1 Reply Last reply Reply Quote 0
          • ferdinandF
            ferdinand @bentraje
            last edited by ferdinand

            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

            MAXON SDK Specialist
            developers.maxon.net

            1 Reply Last reply Reply Quote 1
            • B
              bentraje
              last edited by

              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/3

              RE: 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.

              1 Reply Last reply Reply Quote 1
              • First post
                Last post