Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Make objects to be at the end of the hierarchy list?

    Cinema 4D SDK
    r20 python
    3
    8
    1.1k
    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 it possible to make the identified objects at the end of the hierarchy list?
      You can see an illustration of the problem here:
      https://www.dropbox.com/s/vv0wdhglsnvatxx/c4d102_python_child_at_the_end.jpg?dl=0

      Currently, I'm thinking of this workflow

      1. Store the Child Object/s
      2. GetUp to get the Parent
      3. GetChildren to get all the children of the parent
      4. Filter the children that are not equivalent to 1).
      5. Reparent the filtered children to the Parent in 2)

      It's a bit of a handful. So I was wondering if there is a built-in C4D API function for this process?

      The proper order of the hierarchy is for priority purposes.

      Thank you for looking at the problem.

      1 Reply Last reply Reply Quote 0
      • CairynC
        Cairyn
        last edited by

        I'm not sure if I understand the issue... shouldn't step 1 and 3 yield the same list? What is the filter mentioned in 4.?

        If you just want to put the selected items at the end of the child list, a simple loop would do, where the filtered children are Remove()d and then inserted appropriately at the end?
        (With the necessary precautions for iterating a list that is at the same time being changed)

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

          @Cairyn

          Sorry for the confusion. Referring to my screenshot above.

          1. The store child objects would be Child A and Child B
          2. The parent is the Parent
          3. The children would be Child A, B, C,D ,E
          4. The filtered children would be Child C, D, E (i.e. not Child A and Child)

          You can see a complicated version of what I am working on here:
          https://www.dropbox.com/s/76ye43sge0fa1n1/c4d102_python_child_at_the_end_v1.2.JPG?dl=0

          As you might understand, priorities can be modified with the priorities category and number. However, I want to deal it with the hierarchy. Since its easier to manage.

          I guess I'm looking for a node that says
          "This object should be at the [-1] or [-2] of the list of the children in the heirarchy".

          CairynC 1 Reply Last reply Reply Quote 0
          • CairynC
            Cairyn @bentraje
            last edited by Cairyn

            @bentraje said in Make objects to be at the end of the hierarchy list?:

            As you might understand, priorities can be modified with the priorities category and number. However, I want to deal it with the hierarchy. Since its easier to manage.

            I guess I'm looking for a node that says
            "This object should be at the [-1] or [-2] of the list of the children in the heirarchy".

            Yeah, I'm familiar with the hierarchy/execution sequence issues. Normally I just drag and drop stuff in place, since it's something I do only once, but I admit there are issues with D&D when sub-branches are folded out and sometimes dragged items land on the wrong depth level.

            What I'm not sure about is your functionality, as you seem to have a specific sequence in mind. The easiest way to sort children in an arbitrary manner would be to just select one, and then have a mini script that Remove()s it and InsertAsLast() the removed node. This way you would retain full control over the sort. If you select more than one, you could do the same (just deselect the node so it won't get moved infinite times when you parse the children list) but the selected nodes would stay in the original sequence - so A B C D E F in your example would always become C D E F A B and never C D E F B A. Don't know how you would determine the sub-sequence otherwise. Perhaps by evaluating the selection sequence itself.

            Here's the trivial case where the sequence is determined by the original sequence and the parent is set as the first selected object's parent. This can be easily extended.

            import c4d
            from c4d import gui
            
            def main():
                selectlist = doc.GetSelection() 
                doc.StartUndo()
                if len(selectlist) == 0 : 
                    print "Nothing selected"
                    return
                parent = selectlist[0].GetUp()
                if parent == None :
                    print "No parent"
                    return
                for obj in selectlist: 
                    doc.AddUndo(c4d.UNDOTYPE_HIERARCHY_PSR, obj)
                    obj.Remove()
                    obj.InsertUnderLast(parent)
                c4d.EventAdd()
                doc.EndUndo()
            
            if __name__=='__main__':
                main()
            

            But maybe I'm thinking wrong and the main thing here is the filter?

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

              @Cairyn

              Thanks for the response especially the code. It got me a single crash but currently, it works as expected.

              Though may I ask, why is there a need for the obj.Remove()?
              I deleted the line and it seemed it work as is. The obj.InsertUnderLast() seems to do the work or am I missing something?

              CairynC 1 Reply Last reply Reply Quote 0
              • CairynC
                Cairyn @bentraje
                last edited by

                @bentraje hmm, what caused the crash? I have checked only for two error situations (no selection, and no parent, obviously) so there may be more error situations that need to be caught.

                The "Remove" is just for proper list editing - you normally need to remove a node from a dynamic list so the rest of the list is updated appropriately (e.g. the next node needs to point at the previous node, etc), before you can add the node elsewhere. But it is also possible that InsertUnderLast() takes care of de-linking the node and updating its previous neighbors first, so perhaps removing it is not needed - I couldn't tell because I cannot look into the actual code of InsertUnderLast(). Better to have it there than to crash later on because of improper linkage.

                Note for usage: This code is a script and can only be used in a script. In tags or XPresso nodes, changing the actual object tree is forbidden and may crash C4D (see documentation for Remove() and InsertUnderLast()).

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

                  RE: hmm, what caused the crash? I
                  To be honest, I'm not entirely sure. I was randomly applying it to hierarchies and it just crashed at some point. I was unable to replicate it by then.

                  RE: The "Remove" is just for proper list editing
                  I am under the impression that every object has a unique ID. For instance, Sphere will have a different internal ID with Sphere1 despite both being a sphere primitive.

                  I initially thought Remove will remove/destroy the unique internal ID of the object. So I was dubious in using it.

                  But it doesn't seem to be the case. The PSR constraint, where it references the removed object, is still using the same object after running the code. (i.e. the connectivity still works).

                  Guess, I was wrong all along

                  RE: "In tags or XPresso nodes, changing the actual object tree is forbidden and may crash C4D "
                  Interesting. Thanks for this nugget.

                  Thanks again for the response. Appreciate it a lot.

                  Have a great day ahead!
                  I initially thought.

                  1 Reply Last reply Reply Quote 0
                  • r_giganteR
                    r_gigante
                    last edited by r_gigante

                    Hi @bentraje, thanks for reaching out us.

                    With regard to your question, there's no "straightforward" method delivered, either in Cinema 4D Python API or C++ API, tailored to this specific scope but rather using the approach proposed by @Cairyn is the way to go (and personally I don't find anything clunky).

                    With regard to the GeListNode::Remove() as reported in the documentation it's just responsible for removing a node from a list and in C++ it's also return the object's ownership to the caller freeing Cinema 4D from being responsible to dispose that resource.

                    Best, Riccardo

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