How do I add a face to selection?

I’m implementing my own picking operator, and I’ve managed to do node selection no problem with selectionManager.selectNode(nodeId, SelectionMode.Add), however when it comes to picking a face I run into a problem as there appears to be no public interface to add faces to selection.

I think what I want to do is

const faceSelection = SelectionItem.create(nodeId, null, faceEntity, null, null);
selectionManager.add(faceSelection)

However this doesn’t work because SelectionItem is not an public exported symbol.

Is there another api, or a workaround to the above approach?

Hello @zak,

Given a selected node, are you then trying to highlight a specific face of that node? If that is the case, I think your best bet is to use setNodeFaceHighlighted which takes as parameters the node id and a face id.

Thanks,
Tino

Hey Tino,

Thanks for the response, but no this doesn’t quite do it because I want the selectionManager to be populated with my selection.

For context I’m asking a user to pick a number of faces with a given form control. This control might already have some previously picked faces defined, so I want to load the scene with the selectionManager populated with the existing selection, and allow the user to add/remove the face selection set from that starting point.

Thanks for the clarification, Zak.

So given a faceEntity object, I believe you should be able to just call:

hwv.selectionManager.add(Communicator.Selection.SelectionItem.create(nodeId, null, faceEntity));

…which looks like what you had already tried. In the default Web Viewer that comes with the package, the code snippet above works. You may have to import { SelectionItem } from @hoops\web-viewer\lib\selection\SelectionItem.

Ah yes, ok so what I was doing wrong was trying to import SelectionItem directly, but it is actually imported via Selection.SelectionItem.

Great, thanks! The next question now is how do I construct a faceEntity given a nodeId and the face index?

So if you have the existing selection, you can get the face entity of that selection via the method SelectionItem.getFaceEntity. Or is the face entity still needs to be created?

Ah no unfortunately I don’t. All I have is a list of ids that I match on by iterating the list of faces to find the matching subentityAttribute. This gives me a nodeId, and a faceIndex, but no selection (yet).

So going back to one of your replies:

For context I’m asking a user to pick a number of faces with a given form control. This control might already have some previously picked faces defined, so I want to load the scene with the selectionManager populated with the existing selection, and allow the user to add/remove the face selection set from that starting point.

We actually have an example available in the Communicator package whereby discrete selections can be saved and reloaded just by using the default selection operator. On a selected node, by holding the CTRL key, subentities such as lines and faces can be added (highlighted) or subtracted from the selection set:

To view this example, please do the following:

Thanks, but the default selection operator is not workable for my purposes. I need multi selection with the left click, but crucially I need to add faces to the selection set based on a predicate of the face SubentityAttributes. As far as I can work out, the default operator also doesn’t allow this capability (to add selection to the set programmatically for anything other than NodeId)

Indeed, the selection operation is based on the node id. There is not really a separate face set from the selection, per se. When a node is selected, the face entity, based on the selection point, is highlighted. So there isn’t a separate selection operation on the face entity, it is just highlighted.

As an aside, the default selection operator code is available at HOOPS_Communicator_2024.7.0\web_viewer\deprecated\typescript\operators\SelectionOperator.ts

Ah okay I see, I think I’m misunderstanding the relationships here. So maybe the solution for me does lie in marking a face as highlighted and bookkeeping that on my end. I’ll have a crack at it tomorrow. cheers!

Actually thinking about this further it doesn’t make much sense to me, as the fact that the SelectionItem.create method is public so it stands to reason that I should be able to call it and construct all its arguments. I’ll have a poke around to see how the FaceEntity is constructed internally, I wonder if I can bodge it in.

I’d really rather avoid having to roll my own selection manager when it seems pretty capable of having multiple entities of the same node id type with separate face/line/point entities attached.

Well, given an existing SelectionItem, you can call SelectionItem.getFaceEntity() and then store it, say in an array. At a later time, you can then call SelectionItem.create() to restore it. In this way, you can have the actual FaceEntity objects should you need it to do additional operations and not just highlighted (as described in a workflow in my previous post).

1 Like

Thanks Tino,

I’ve managed to resolve this by extracting enough face data to reconstruct the face entity object with enough to satisfy the selection manager. Some fields are not valid but that seems to be ok for my purposes.

      const faceEntity = new Selection.FaceEntity(
        faceDirection.origin,
        faceDirection.normal,
        selection.propertyIndex,
        0,
        0,
        new Box(),
        false,
      );

      this.viewer.selectionManager.add(Selection.SelectionItem.create(selection.nodeId, null, faceEntity, null, null));
1 Like