Delete hide objects script


#1

Hi all,
I’m not very good in python script, but I suppose it’s the best way to do it.

I need to delete all the objects with the “Visible in Editor” = Off that I’ve selected in my scene.
But I got some scene with 100000 objects and 50000 of them are hide, and I have no time to select 50000 objects one by one, I hope you understand it.

How I can do it?


#2

It’s not really difficult and I’ll provide a small code snippet.
But there’s a small inconsistency, which makes me as a coder stumble. A common problem of coders, we sit too much, therefore walking is already difficult and then the smallest irritation…

You want to have deleted all objects, which have “Visible in Editor == Off” and you have selected. But then you say, you won’t have the time to select 50000 objects. So, what’s the actual condition? Only “Visible in Editor == Off”? Or “Visible in Editor == Off” and “selected”?

And do you have any other constraints? Should it consider the entire hierarchy? Or maybe only top-level objects?

If you want to do it yourself:

  1. Start with first object (BaseDocument.GetFirstObject())
  2. Iterate the hierarchy (GeListNode.GetDown() and GeListNode.GetNext() (every BaseObject is a GeListNode),
    per object:
    • Check editor visibility (parameter ID: ID_BASEOBJECT_VISIBILITY_EDITOR)
    • Delete object (GeListNode.Remove())

Cheers


#3

So, here you go.
Simply load or (better import) the attached script into the Script Manager.

Regarding my above question, see lines five and six of the script.
As it is now (line 6 commented) it will delete only selected objects with editor visibility off.

If you uncomment line 6, it will delete all objects with editor visibility off.

NOTE: In current state the script will only pay attention to the selection state of objects in the first Object Manager. (as Cairyn pointed out below, all Object Managers share the same object selection)

delete_objects.py (849 Bytes)

Cheers

# This script conditionally removes objects from the scene.
import c4d

# Set the condition for removal
# Choose a line or add a new one yourself:
Condition = lambda o: o[c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] == 1 and o.GetBit(c4d.BIT_ACTIVE) == True
#Condition = lambda o: o[c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] == 1

def DoRemove(obj):
    doc.AddUndo(c4d.UNDOTYPE_DELETE, obj)
    obj.Remove()

def WalkObjects(obj, cond, do):
    while obj is not None:
        objNext = obj.GetNext()
        if obj.GetDown() is not None:
            WalkObjects(obj.GetDown(), cond, do)
        if cond(obj):
            do(obj)
        obj = objNext

def main():
    obj = doc.GetFirstObject()
    doc.StartUndo()
    WalkObjects(obj, Condition, DoRemove)
    doc.EndUndo()
    c4d.EventAdd()

if __name__=='__main__':
    main()

EDIT: As Cairyn pointed out, the first version posted here, was a pile of dinosaur poo. I fixed it in this post, not so much to hide my incompetence, but rather to avoid a future reader grabbing a broken version.


#4

Thank you MighT24 for your interest,
I’ve tryed your script, but it do not what I need :frowning:

Take a look at the image, this is an example of what the script should to do on a simple scene.
Of course, I have to select al the object in the tree where the script have to works.


#5

Actually, that should be what the script does?

How are the script’s results different from what you show here?


#6

That’s actually exactly, what the script should do.

As I wrote above, if you use the script as is, you will need to select all objects, which are supposed to be deleted. In other words, from all selected objects it will delete those, which have editor visibility set to off. As I wasn’t sure, how you’d like to have it, I deemed this more “defensive”.

If you want it to delete ALL objects with editor visibility off, simply remove the hash tag (#) at the beginning of line six.


#7

Shouldn’t the selection state AND the visibility state be the same for all object managers?

Also: I am surprised that the script works, as the obj is first Remove()d and then its Next and Down pointers are accessed afterwards (and eligible children are Remove()d even later from the already-unlinked tree section). I assume that the obj’s pointers are kept alive internally as the obj still exists as part of the undo functionality? (Not complaining, just curious…)


#8

Oh, sh#t!
Thanks!!! I should really think, before posting. Will be fixed


#9

I’ve run the script
on the example scene (in my image) and my result is:

A
-B1
–C.2
–C.3
Null.1

The C.3 object should be deleted. But it’s remain.
To delete it too, I have to run the script again.

And, for example, If I select only the objects:

C.1

B2
-Null
-Cube

the script run over all the objects in the scene, not only in the selected objects.


#10

Please try this new script:
delete_objects.py (849 Bytes)

The issue Cairyn pointed out is acttually pretty bad and may well lead to unintended behaviour.

Edit: I’l also fix it in the first post.


#11

Oh man, this WORKS VERY FINE NOW!!!

Thank you very much, you’re so precious!


#12

Welcome :slight_smile:

Though I’d rather have posted this without the need for Cairyn to teach me the basics… quite embarassing…

@Cairyn Once more, you are right. I never thought about it. I simply always assumed the bits BIT_ACTIVE2 and BIT_ACTTIVE3 would behave somewhat orthogonal to the NBITs and never questioned it. Now, thinking about it, it would indeed imply pretty strange behaviours or at least confusing workflows, if it was possible to have multiple different object selections. Thanks for making me aware and pointing it out. I’ll remove the hint from first post.