Preselection with -_SelLayer _Pick

Hi All,

I have an object preselected. Then I do:
-_SelLayer _Pick
My previously selected object is still selected.
I hit enter.

The selection does not change. I still have the initially selected object selected, but no other objects of the layer got selected. If I select the object inside the command, the other objects of the layer get selected as expected.

I would like the preselected object being used for the -_SelLayer _Pick. Can I adjust the macro to do so or is this not possible?

Thanks

Seems like this may not be possible - looks like a bug or an oversight…

Here is both a VB rhinoscript and a Python script (in case you’re on Mac) that do what you want…

–Mitch

Option Explicit

Call SelLayerEx()
Sub SelLayerEx()
    Dim objs, obj
    Rhino.UnselectAllObjects()
    objs = Rhino.GetObjects("Select objects",,, True)
    If Not IsArray(objs) Then Exit Sub
    Call Rhino.EnableRedraw(False)
    For Each obj In objs
        Call Rhino.ObjectsByLayer(Rhino.ObjectLayer(obj), True)
    Next
    Call Rhino.EnableRedraw(True)
End Sub
import rhinoscriptsyntax as rs

def SelLayerEx():
    rs.UnselectAllObjects()
    objs = rs.GetObjects("Select objects",preselect=True)
    if not objs: return
    rs.EnableRedraw(False)
    for obj in objs:
        rs.ObjectsByLayer(rs.ObjectLayer(obj), True)
SelLayerEx()

Hi Mitch, awesome. Many thanks for the scripts!

Mitch,

I made your script into a Rhinopython command within a plugin. Lets assume the command is called MitchSelLayer. I use it as follows in a macro:

_MitchSelLayer _Pause _Invert _Hide

Problem is, the macro does not stop at the _Pause, but hides all objects in the document. It does not seem to wait for the script to complete.

Any ideas?

Thanks

I don’t know - I’ve never used scripts in that way… I just have a tendency to integrate all the functions in the script itself. So you are trying to hide all other objects except those on selected layers? That’s just another couple of lines in the script. --Mitch

import rhinoscriptsyntax as rs

def SelLayerInvHide():
    rs.UnselectAllObjects()
    objs = rs.GetObjects("Select objects",preselect=True)
    if not objs: return
    rs.EnableRedraw(False)
    for obj in objs:
        rs.ObjectsByLayer(rs.ObjectLayer(obj), True)
    toHide=rs.InvertSelectedObjects()
    if toHide: rs.HideObjects(toHide)
SelLayerInvHide()

Thanks a lot for adding to the script. I was starting to like macros to make quick aliases. I would have used the MitchSelLayer in around 8 macros. I think I have to go back to scripting due to the limitations of macros to work in combination with scripts.

Hi Mitch, Silvano - this is probably by design, since it allows you to add specific layers’ objects to your current selection - I guess, absent another command line option, the right way is a matter of context- hard to win.

http://mcneel.myjetbrains.com/youtrack/issue/RH-30433

-Pascal

RH-30433 is fixed in the latest WIP

@pascal @dale May the dash command with objects preselected be adjusted to complete without an additional _Enter? This seems like many other commands behave.

Current command flow:

  1. Select objects in view
  2. -_SelLayer _Pick
  3. Hit enter

Wished for command flow:

  1. Select objects in view
  2. -_SelLayer _Pick → completes

I know this can be done with a script (see below). I am asking, because I need a version for my students that works without installing anything.


For others, that look for a solution that also stays within the space you are in, you can use the following script to achieve this.

#! python 3
"""
Select objects on the layers of the selected objects. Allows preselect.

The selection stays inside the active view. In model space only model objects
are picked up, in a layout only the objects sitting on that page. With a
detail view active the command works in model space and objects outside the
detail window stay unselected (avoids accidental deletions of invisible objects).
"""

import Rhino
import rhinoscriptsyntax as rs
import scriptcontext as sc


def filter_space(view):
    if isinstance(view, Rhino.Display.RhinoPageView):
        if view.ActiveViewport.Id != view.MainViewport.Id:
            # A detail is active, it shows model space
            return Rhino.DocObjects.ActiveSpace.ModelSpace
        return Rhino.DocObjects.ActiveSpace.PageSpace
    return Rhino.DocObjects.ActiveSpace.ModelSpace


def detail_viewport(view):
    if not isinstance(view, Rhino.Display.RhinoPageView):
        return None
    if view.ActiveViewport.Id == view.MainViewport.Id:
        return None
    return view.ActiveViewport


def objects_of_view(obj_ids, view):
    space = filter_space(view)
    page_id = None
    if space == Rhino.DocObjects.ActiveSpace.PageSpace:
        # Page space objects carry the id of the layout they sit on
        page_id = view.MainViewport.Id
    viewport = detail_viewport(view)
    res_objs = []
    for obj_id in obj_ids:
        obj = sc.doc.Objects.FindId(obj_id)
        if not obj:
            continue
        if obj.Attributes.Space != space:
            continue
        if page_id and obj.Attributes.ViewportId != page_id:
            continue
        if viewport:
            # Only what the detail camera looks at
            bbox = obj.Geometry.GetBoundingBox(True)
            if not bbox.IsValid:
                continue
            if not viewport.IsVisible(bbox):
                continue
        res_objs.append(obj_id)
    return res_objs


def main():
    objs = rs.GetObjects("Select objects", preselect=True)
    if not objs:
        return
    rs.EnableRedraw(False)

    layers = [rs.ObjectLayer(o) for o in objs]
    layers = set(layers)

    # Get objects by layer
    res_objs = []
    for lay in layers:
        if lay is not None:
            sel_objs = rs.ObjectsByLayer(lay, False)
            if sel_objs:
                res_objs.extend(sel_objs)

    # Keep the objects of the active view only
    view = sc.doc.Views.ActiveView
    if view:
        res_objs = objects_of_view(res_objs, view)

    # Select
    rs.UnselectAllObjects()
    rs.SelectObjects(res_objs)
    rs.EnableRedraw(True)


if __name__ == "__main__":
    main()