Isotropix Forums

Filter objects by type in OfObjectArray()

Clarisse Scripting related topics

Filter objects by type in OfObjectArray()

Unread postby vishumish » Tue Jul 07, 2020 1:11 pm

Hi,
I have following questions related to querying objects from a clarisse scene :

1) I want to filter out objects of some specific class from following objects_array. Is there any pythonic way to filter them within the get_all_objects method call only.

For example : I want to filter out Images from objects_array in the following code snippet:

python code

objects_array = ix.api.OfObjectArray()
ix.application.get_factory().get_all_objects(objects_array)


2) Is there a quick way to convert OfObjectArray() and OfContextSet to a python list?
3) Is there a way to get disable and enable property of a reference attr (like Active camera, renderer etc?
4) Also is there any quick way to fetch all the remote objects within a clarisse scene? Right now I am checking is_remote property of every object recursively.
5) One more thing about querying remote objects. I have a parent clarisse scene where i have another child clarisse scene as reference. The top most node (The context node labelled as the child file name having filename, reload, clear cleanup options in attribute editor) is not considered as remote. Please see following :

python code

item = ix.get_item("project://blank_scene")
print item.is_remote()

Here item.is_remote is giving me False, even though when the "project://blank_scene" is another project file that I have pulled as a reference.
6) Adding one more point about querying disable/enable state of layer3d reference attributes like active camera, renderer, shadow, geometry, gi. How can I query them as boolean value?

Regards,
-Vishal
vishumish
 
Posts: 16
Joined: Mon Jan 27, 2020 11:38 am

Re: Filter objects by type in OfObjectArray()

Unread postby anemoff » Mon Jul 20, 2020 11:24 am

Hi!

1) To filter objects by type, specify the class name as 1st parameter

python code

# get all Light objects
objects_array = ix.api.OfObjectArray()
ix.application.get_factory().get_all_objects('Light', objects_array)

You can use the Class Explorer widget to explore class names.

2) Convert array to set: you have to do it manually, I'm a bit surprised we don't have an API for that.

python code

objects_set = ix.api.OfObjectSet()
for obj in objects_array:
objects_set.add(obj)


3) For a reference attribute, you need to get the referenced object with 'OfAttr::get_object' and then use 'OfItem::is_disabled'
By default, 'get_object' (without arguments) will return None if the referenced object is disabled or muted, as if there was no object assigned at all.

python code

layer3D = ix.get_item('project://scene/image.background')
# get the object only if assigned and enabled:
camera = layer3D.get_attribute('active_camera').get_object()
if camera:
print('active camera is: {}'.format(camera))
else:
print('no camera assigned to layer3D, or is disabled')


If you need to get the object regardless of its state, you need to specify all arguments as follows:

python code

camera = layer3D.get_attribute('active_camera').get_object(0, ix.api.OfAttr.VALUE_PAGE_CURRENT, False)
if camera:
# there is a camera assigned, but it might be disabled
if camera.is_disabled():
print('camera {} is disabled'.format(camera))
else:
print('camera {} is enabled'.format(camera))
# do something with the camera
else:
print('no camera assigned to layer3D')


4) Getting all remote objects: there's no straightforward API for that, using is_remote is a good workaround for now

5) The top reference context is never remote, however, its contents, including nested references, are. Not a bug.
But you can use 'OfContext::is_reference' to test if a context is a reference context (project, abc or usd).

6) If I understood correctly, you want to query a reference attribute as a boolean (true == there's an object assigned, false == no object)
You could use:

python code

has_object = reference_attr.get_object() is not None


Cheers,
Anthony Nemoff
Isotropix
R&D Engineer
User avatar
anemoff
 
Posts: 321
Joined: Wed Jan 13, 2016 10:10 am

Re: Filter objects by type in OfObjectArray()

Unread postby anemoff » Mon Jul 20, 2020 3:32 pm

Here are 2 approaches to get only the remote objects:

python code

import time

def get_remote_objects_recursive(context, result):
# first, get direct children objects that are remote
sub_objects = ix.api.OfObjectArray()
mask = ix.api.CoreBitFieldHelper(True, ix.api.OfItem.FLAG_REMOTE) # mask to get remote objects only
context.get_objects(sub_objects, mask)
for obj in sub_objects:
result.add(obj)

# finally, process each sub-context recursively
sub_contexts = ix.api.OfContextSet()
context.resolve_contexts(sub_contexts)
for sub_context in sub_contexts:
get_remote_objects_recursive(sub_context, result)

def get_project_remote_objects():
start = time.time()
remote_objects = ix.api.OfObjectSet()
get_remote_objects_recursive(ix.application.get_factory().get_root(), remote_objects)
print 'time: {} s'.format(time.time() - start)
print 'remote objects (smart):', remote_objects.get_count()
for obj in remote_objects:
print obj
return remote_objects

def get_project_remote_objects_brute_force():
start = time.time()
all_objects = ix.api.OfObjectArray()
ix.application.get_factory().get_all_objects(all_objects)

remote_objects = ix.api.OfObjectSet()
for obj in all_objects:
if obj.is_remote():
remote_objects.add(obj)

print 'time: {} s'.format(time.time() - start)
print 'remote objects (brute force):', remote_objects.get_count()
for obj in remote_objects:
print obj
return remote_objects

print '*' * 50

get_project_remote_objects()
print ''
get_project_remote_objects_brute_force()
Anthony Nemoff
Isotropix
R&D Engineer
User avatar
anemoff
 
Posts: 321
Joined: Wed Jan 13, 2016 10:10 am

Re: Filter objects by type in OfObjectArray()

Unread postby vishumish » Tue Jul 21, 2020 7:34 am

Hi Anthony, Thanks a lot for writing down all the answers. However for question number one (filter objects by type) I was asking for something else.

1) Let me give you an example, in following code :

python code

objects_array = ix.api.OfObjectArray()
ix.application.get_factory().get_all_objects(objects_array)


This will give me all objects in the scene but I don't want few objects in that list such as :
"project://__system_vars",
"project://__builtin_vars",
"project://__custom_vars",
"project://__app_prefs_vars",
"project://__project_prefs_vars",
"project://ping",
"project://clone_stamp_3d",
"project://particle_paint",
"project://property_paint",
"project://pick_fit",
"project://picker",
"project://render_region",
"project://rotate_item",
"project://scale_item",
"project://select",
"project://translate_item",
"project://ruler",
"project://Shelf",
"project://log",
"project://browser",
"project://script_editor",
"project://__OSL__1",
"project://__Python__1",
"project://attribute_editor",
"project://__Python__",
"project://hierarchy_view",
"project://group",
"project://__Python__2",

So just want to know if I can exclude them by their class name or in some other way.

2) Also is there a quick way to query all objects within a context? Right now I am doing it brutforce way.

Thanks!
vishumish
 
Posts: 16
Joined: Mon Jan 27, 2020 11:38 am

Re: Filter objects by type in OfObjectArray()

Unread postby mdevaux » Tue Jul 21, 2020 8:52 am

for 1), try this instead:
ix.application.get_factory().get_all_objects("ProjectItem", objects_array)

The API does not handle any exclusion filters, but providing the "ProjectItem" class filter will filter out objects you're not interested in, such as widgets, tools, vars.

For 2)
ctx_children = ix.api.OfObjectArray()
ctx = ix.get_item("project://the_path_to_context_to_query")
ctx.get_all_objects(ctx_children)

Actually, ix.application.get_factory().get_all_objects is a shortcut for calling the method above on the root context.

Hope this helps.
--
Marianne.
User avatar
mdevaux
 
Posts: 21
Joined: Tue Apr 26, 2016 2:05 pm

Re: Filter objects by type in OfObjectArray()

Unread postby vishumish » Tue Jul 21, 2020 2:16 pm

Thanks a lot Marianne, Both the solutions are pretty much solving my requirement.
I tried both ways a while back. Couldn't remember why it didn't work out (I guess I got lost somewhere). But thanks again for the help, its working :)
vishumish
 
Posts: 16
Joined: Mon Jan 27, 2020 11:38 am

Re: Filter objects by type in OfObjectArray()

Unread postby vishumish » Thu Jul 23, 2020 9:41 am

Hi Animoff, I just realized that the snippet you suggested to "get only the remote objects" is getting stuck in an infinite loop (first approach). I would fix it at my end though but would be good if you can fix it here for others who are looking for something similar. Also the mask example is not working for me. Its returning 0 objects and not giving any error. I am using clarisse 3.6.

I have one more question i.e., following code is not taking account of disabled items in the project.

python code

objects_array = ix.api.OfObjectArray()
ix.application.get_factory().get_all_objects("ProjectItem", objects_array)

It's not including disabled items in the project. However from your example I got the idea that I could use "mask" for it but its not working. I want to fetch objects which are disabled and locked separately. Please help!

Thanks
-Vishal
vishumish
 
Posts: 16
Joined: Mon Jan 27, 2020 11:38 am

Re: Filter objects by type in OfObjectArray()

Unread postby anemoff » Thu Jul 23, 2020 11:05 am

Hi Vishal,

About the infinite loop that freezes Clarisse, it's a bug (#10536) that has been fixed in 4.0 SP7.

Check this post and the following answers for more details on fetching objects and CoreBitFieldHelper.
By default "ix.application.get_factory().get_all_objects("ProjectItem", objects_array)" will return only enabled items.
To get all items, even disabled, you can specify an empty mask like this:

python code

objects_array = ix.api.OfObjectArray()
empty_mask = ix.api.CoreBitFieldHelper()
ix.application.get_factory().get_all_objects("ProjectItem", objects_array, empty_mask)



To get only locked items, the mask would be:

python code

locked_mask = ix.api.CoreBitFieldHelper(True, ix.api.OfItem.FLAG_USER_LOCKED)


I invite you to read the documentation of OfItem::Flag and CoreBitFieldHelperto understand how to build custom masks. Note that documentation on 3.6 is incomplete, so read the 4.0 one.

I'll check why the mask isn't working in 3.6 in some APIs.

Cheers,
Anthony Nemoff
Isotropix
R&D Engineer
User avatar
anemoff
 
Posts: 321
Joined: Wed Jan 13, 2016 10:10 am


Return to Scripting
cron