Find current selection's subobjects' ids in RhinoCommon

Hi there,

let’s say I wanted to take the current selection in the model and check if I selected sub-objects (especially then figuring out which block it originates from, trying this approach:

My code for reading the sub-objects is this one, but I always just am able to get back the top-level object.

ObjectEnumeratorSettings settings = new ObjectEnumeratorSettings();
settings.SelectedObjectsFilter = true; 
settings.SubObjectSelected = true;
settings.

var selection = Document.Objects.FindByFilter(settings);

foreach (RhinoObject obj in selection)
{

    var instanceObject = obj as InstanceObject;
    if (instanceObject != null)
    {
        ObjRef oRef = new ObjRef(obj);
        if (!oRef.GeometryComponentIndex.IsUnset())
        {
            var subObject = instanceObject.SubObjectFromComponentIndex(oRef.GeometryComponentIndex);
    
            // ... Other code here
        }
    }
}

Any ideas anyone?

Thanks,
T.

the following script (via scripteditor ) will duplicate all geometry sub-Selected from blocks…
hope this helps as a starting point
… not sure if there is a more direct / simpler way or if this is the approach the api wants us to do it…

// #! csharp
using System;
using Rhino;
using Rhino.DocObjects;
using Rhino.Geometry;

ObjectEnumeratorSettings settings = new ObjectEnumeratorSettings();
settings.SelectedObjectsFilter = true; 
settings.SubObjectSelected = true;

var selection = __rhino_doc__.Objects.FindByFilter(settings);

foreach (RhinoObject obji in selection)
{
    // check if Instance and cast
    if (obji.ObjectType == ObjectType.InstanceReference && obji is InstanceObject instance )
    {
        // get the transform
        Transform xform = instance.InstanceXform;
        // iterate all subselections 
        foreach( ComponentIndex ci in obji.GetSelectedSubObjects())
        {
            if (ci.ComponentIndexType == ComponentIndexType.InstanceDefinitionPart)
            {
                // next line - maybe do stepwise for better debugging / errorhandling
                GeometryBase geo = instance.InstanceDefinition.GetObjects()[ci.Index].Geometry;
                GeometryBase geoNew = geo.Duplicate();
                if (geoNew.Transform(xform))
                {
                    __rhino_doc__.Objects.Add(geoNew);
                }
            }
        }
    }
}

@Tom_P, thanks.

This does somehow not work for me.
@dale may I ask what is the ComponentIndex referring to when I am picking an object from a nested block?
The ci.ComponentIndexType == ComponentIndexType.InstanceDefinitionPart is true, but I have no idea how to make use of it!

Thanks a lot,
T.

Hi @tobias.stoltmann,

What is your goal - what problem are you trying to solve?

Thanks,

– Dale

@dale
When working in a model I want to read the currently selected objects.
No problem at all when no subobjects are selected.

In case subobjects are selected (and in my particual case it would be parts of nested blocks), I would like I am trying to find out which block the selected objects belongs to.

I just saw that @lars has answered this question some time ago here.

I tried this a few days ago though and it did not work.
(Might try this again right now).

I’m trying understand what this means.

For example, if you’ve selected an edge of a Brep, what do you want back?

Same with a sub-object of a instance reference, what do you want back?

– Dale

@dale sorry for being so unspecific.

Let’s say I subselect the red panel (which is a block) inside the main block, my aim would be to get the id of the selected panel.
This works fine when I do it with a GetObject() object, yet for me it does not work when I do it like this:

ObjectEnumeratorSettings xsettings = new ObjectEnumeratorSettings();
settings.ReferenceObjects = true;
settings.ActiveObjects = true;
settings.SelectedObjectsFilter = true;
settings.SubObjectSelected = true;

var test = Document.Objects.FindByFilter(settings);

foreach (var rhObj in test)
{
    RhinoObject subObject = null;
    ObjRef obj = new ObjRef(rhObj);
    var instanceObject = obj.Object() as InstanceObject;
    if (instanceObject != null)
    {
        if (!obj.GeometryComponentIndex.IsUnset())
        {
            subObject = instanceObject.SubObjectFromComponentIndex(obj.GeometryComponentIndex);
        }
    }

    if (subObject != null)
    {
        // here I have methods for finding out which block the item belongs to
    }
}

I hope that this example makes it less abstract.

The id of the instance object (you said this is a sub-block)?

The id of the instance definition of this instance object?

The id of the instance definition geometry (of the instance definition of this sub-block)?

lol

– Dale

:grinning_face: Touche!

Ideally I would like the name of the InstanceDefinition that contains the subselected geometry.
This seem impossible, at least from what I understood.
So it would be sufficient for me to get the GUID or RhinoObject that this geometry belongs to.

This woudl come close to this one. If this is not possible it would be the id of the RhinoObject that I subselected.

Hi @tobias.stoltmann,

Seem like this is what you want:

// #! csharp
using System;
using Rhino;
using Rhino.DocObjects;
using Rhino.Geometry;

ObjectEnumeratorSettings settings = new ObjectEnumeratorSettings
{
    SelectedObjectsFilter = true,
    SubObjectSelected = true
};

RhinoObject[] selectedObjects = __rhino_doc__.Objects.FindByFilter(settings);
foreach (RhinoObject rhObj in selectedObjects)
{
    if (rhObj is InstanceObject instanceObj)
    {
        InstanceDefinition instanceDef = instanceObj.InstanceDefinition;
        if (instanceDef != null)
            RhinoApp.WriteLine($"Instance definition: {instanceDef.Name}");
    }
}

What am I missing?

– Dale

@dale thanks!
This gives me the superior block’s definition’s name.
The result is: “Panel and profile”.
The desired result would be to get back the rhino-object’s id that I selected. Using this I can find out which block it belongs to and get the following result: “Profile”.

The purpose of this is to be able to select items from nested blocks and to assign user-texts to it’s definition without having to open the blockeditor every time, searching for the block’s name, …

Hi @tobias.stoltmann,

Give this a try - you can run from the ScriptEditor.

Tobias.cs (3.1 KB)

– Dale

@dale!
This is it.
A wholehearted: Thank you very much!

:person_bowing:

@dale
Just a last question here.
Do you think it’s possible to retrieve the “parent” object’s ID here as well?
Referring to the schematic picture this would mean:
I now successfully got the definition “Panel” and would like to get the “Panel and profile” instance’s Id.

Hi @tobias.stoltmann,

Referencing the code I posted last week, the owning instance object is the Id of instanceObject:

// Find selected instance objects
if (selectedObject is InstanceObject instanceObject)

Is that what you want?

– Dale

@dale yes and no :slight_smile:

I think I am having trouble to articulate the problem, honestly - and I am really sorry for stealing your time on this one.

As this is a really essential problem I am facing right now I will try to be more specific and I hope I am able to describe it properly now.

TEST.3dm (805.9 KB)

I am trying to assing user data to objects.
My aim is that I want to avoid that my colleauges always have to go to the block editor, searching for nested definitions to assign user data.
What I am talking about is

  • assigning user data to block definitions (= the parts descriptions themselves)
  • assigning user data to instanciations of the definitions

This is of course totally easy on the top level.
Assigning to the block definition itself is totally sovled with your solution!
The (really) last challenge is that if a sub-object is selected we want to assign user-data to the selected instance. This might even mean that you have the same definition instanciated on the same level multiple times, but only one of them gets a specific value, e.g. color or something similar for production.

I already have a code doing this and this work perfectly fine when I use the GetObject() class.
Somehow it does not work with the filter that gets the selected objects. You might say that you wanna see this code, but I would not wanna steal any of your time for this (honestly).

So in short - if you sub-select the red object in the attache file:
Is it possible to return the id of the instance object: 719127a1-0482-4292-9022-5a8f322beeac.

I am really sorry for the confusion, honestly nested blocks have been both toruting and fascinating me big time… :slight_smile:

The result of this will ease at least 8 peoples’ daily life also big time, so it is worth getting on your nerves :slight_smile:

Thanks big time again!
T.

@tobias.stoltmann - hopefully I can get to this tomorrow.

@dale thanks and no rush!

Hi @tobias.stoltmann,

After some investigating, we looks like we will need to add something addition to RhinoCommon for you to get the owning sub-instance object of a selected sub-object in an instance object (if that’s clear).

When selecting sub-objects in an instance object, Rhino hands the developer the actual underlying object, as that is what most devs are looking for. There is no clear way to just get the selected sub-object as a instance object.

– Dale

@dale, understood.
Would be great if there was a way to make this work.