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



  • 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.



  • 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)



  • @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".



  • @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?



  • @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?



  • @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()).



  • 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.



  • 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


Log in to reply