Set Layer Visibility issue

Hi,

I found that pythons rhinoscriptsyntax.LayerVisible is doing something wrong when setting sublayers:

As you can see, when I turn the layer of manually it’s truly off
With the scripted method, the layer comes in a state it should not even be in with the Parent layer turned ON.
It causes the layers turned off by the script to pop back on again when an event ‘updates’ the layer visibilities.

Thanks
-Willem

Yep, this has been wrong for ages… IIRC, it’s just the lightbulb display in the layer box that is incorrect, not the actual layer’s visibility state. Or there is a new problem…

–Mitch

Well this works:

' RhinoScript
Rhino.AddLayer "TEST::SUB"
Rhino.LayerVisible "TEST::SUB", False

@Alain, can you log this as a Python bug?

That goes deeper than the Python level. I’ll take a look.

logged.

Thanks for reporting.

1 Like

What’s the state on this topic?

I’m trying to bake geometry to three sublayers and turn off two of them and then collapse the parent layer.

rs.ExpandLayer turns the sublayers back on.

Without rs.ExpandLayer it works until I manually collapse and expand the parent layer. Then the sublayers are on again.

I also find that this behavior of rs.LayerVisible(name,visible=False) very confusing. To me it seems that I can not completely turn off layers via rhinoscript. I am only able to turn them half off. Half turned off Layers turn back on when collapsing and expanding the parent layer.
Please advice for workarounds, if possible.

Hi Goswin,

The easiest way to “fix” this is to add the following statement to the LayerVisible implementation found in layer.py:

def LayerVisible(layer, visible=None, force_visible=False):
    """Returns or changes the visible property of a layer.
    Parameters:
      layer = name of existing layer
      visible[opt] = new visible state
    Returns:
      if visible is not specified, the current layer visibility
      if visible is specified, the previous layer visibility
    """
    layer = __getlayer(layer, True)
    rc = layer.IsVisible
    if visible is not None and visible!=rc:
        if visible and force_visible:
            scriptcontext.doc.Layers.ForceLayerVisible(layer.Id)
        else:
            layer.IsVisible = visible
            "" ** ADD THIS **
            layer.SetPersistentVisibility(visible)
            "" **************
            layer.CommitChanges()
        scriptcontext.doc.Views.Redraw()
    return rc

Does this help?

– Dale

1 Like

Dale and @sbaerdev, yes this helps! Thank you. I created a pull request for it too:

1 Like

CC @Alain

Looks like this is fixed in the latest here.

-Pascal

RH-32245 is fixed in the latest WIP

For Python, I found in the latest WIP that “layer.CommitChanges()” was missing to actually switch the layer light bulb state.
I tried to make the one-line fix in layers.py and the strangest thing happened, I altered layers.py file for the LayerVisible function, and moved the code position to insert a new addition, but when running code to debug, the debugger was pointing to the original code location and ignoring changes. Also the cursor was jumping to where the old code used to be and seemed to be executing code even thought text was where it was pointing.

Not being able to “fix” the lightbulb half-off issue, I simply copied code from Rhino6 WIP and added the missing activation line, then copied the necessary includes and functions not accessible to my program. Lastly, I removed the rs. in front of the LayerVisible commands in the program since I’m executing local functions.

Here is the complete code section added to my program. A bit ugly, but it works without altering the master code files.

#------------------------------------------------------

A replacement for layer visible half-lightbulb error

#------------------------------------------------------

import Rhino.DocObjects.Layer
import scriptcontext
import System.Guid

def LayerVisible(layer, visible=None, forcevisible_or_donotpersist=False):
""“Returns or changes the visible property of a layer.
Parameters:
layer (str): name of existing layer
visible (bool, optional): new visible state
forcevisible_or_donotpersist (bool, optional): if visible is True then turn parent layers on if True. If visible is False then do not persist if True
Returns:
bool: if visible is not specified, the current layer visibility
bool: if visible is specified, the previous layer visibility
”""
layer = __getlayer(layer, True)
rc = layer.IsVisible
if visible is not None:
layer.IsVisible = visible
if visible and forcevisible_or_donotpersist:
scriptcontext.doc.Layers.ForceLayerVisible(layer.Id)
if not visible and not forcevisible_or_donotpersist:
layer.SetPersistentVisibility(visible)
layer.CommitChanges()
scriptcontext.doc.Views.Redraw()
return rc

def __getlayer(name_or_id, raise_if_missing):
if not name_or_id: raise TypeError(“Parameter must be a string or Guid”)
id = coerceguid(name_or_id)
if id: name_or_id = id
else:
layer = scriptcontext.doc.Layers.FindByFullPath(name_or_id, True)
if layer>=0: return scriptcontext.doc.Layers[layer]
layer = scriptcontext.doc.Layers.Find(name_or_id, True)
if layer>=0: return scriptcontext.doc.Layers[layer]
if raise_if_missing: raise ValueError("%s does not exist in LayerTable" % name_or_id)

def coerceguid(id, raise_exception=False):
if type(id) is System.Guid: return id
if type(id) is str and len(id)>30:
try:
id = System.Guid(id)
return id
except:
pass
if (type(id) is list or type(id) is tuple) and len(id)==1:
return coerceguid(id[0], raise_exception)
if type(id) is Rhino.DocObjects.ObjRef: return id.ObjectId
if isinstance(id,Rhino.DocObjects.RhinoObject): return id.Id
if raise_exception: raise TypeError(“Parameter must be a Guid or string representing a Guid”)

#-----------------------------------

I assume this will be corrected for Rhino6, but there are a lot of Rhino5 users stuck with this problem.

Regards, Ray

H

The above code listing is poor, so here is a text file with correct formatting.
fix_layer.py (2.6 KB)

Hi Ray

Thanks for sharing! I’ll paste the code below with formatting preserved by surrounding it like so:

```python
<code here>
````
#------------------------------------------------------
# A replacement for layer visible  half-lightbulb error
#------------------------------------------------------
# for layer light turn off completely
import Rhino.DocObjects.Layer
import scriptcontext
import System.Guid

def LayerVisible(layer, visible=None, forcevisible_or_donotpersist=False):
    """Returns or changes the visible property of a layer.
    Parameters:
      layer (str): name of existing layer
      visible (bool, optional): new visible state
      forcevisible_or_donotpersist (bool, optional): if visible is True then turn parent layers on if True.  If visible is False then do not persist if True
    Returns:
      bool: if visible is not specified, the current layer visibility
      bool: if visible is specified, the previous layer visibility
    Example:
      import rhinoscriptsyntax as rs
      layers = rs.LayerNames()
      if layers:
      for layer in layers:
      if rs.LayerVisible(layer)==False:
      rs.LayerVisible(layer,True)
    See Also:
      LayerLocked
    """
    layer = __getlayer(layer, True)
    rc = layer.IsVisible
    if visible is not None:
        layer.IsVisible = visible
        if visible and forcevisible_or_donotpersist:
            scriptcontext.doc.Layers.ForceLayerVisible(layer.Id)
        if not visible and not forcevisible_or_donotpersist:
            layer.SetPersistentVisibility(visible)
        layer.CommitChanges()
        scriptcontext.doc.Views.Redraw()
    return rc
def __getlayer(name_or_id, raise_if_missing):
    if not name_or_id: raise TypeError("Parameter must be a string or Guid")
    id = coerceguid(name_or_id)
    if id: name_or_id = id
    else:
        layer = scriptcontext.doc.Layers.FindByFullPath(name_or_id, True)
        if layer>=0: return scriptcontext.doc.Layers[layer]
    layer = scriptcontext.doc.Layers.Find(name_or_id, True)
    if layer>=0: return scriptcontext.doc.Layers[layer]
    if raise_if_missing: raise ValueError("%s does not exist in LayerTable" % name_or_id)
def coerceguid(id, raise_exception=False):
    if type(id) is System.Guid: return id
    if type(id) is str and len(id)>30:
        try:
            id = System.Guid(id)
            return id
        except:
            pass
    if (type(id) is list or type(id) is tuple) and len(id)==1:
        return coerceguid(id[0], raise_exception)
    if type(id) is Rhino.DocObjects.ObjRef: return id.ObjectId
    if isinstance(id,Rhino.DocObjects.RhinoObject): return id.Id
    if raise_exception: raise TypeError("Parameter must be a Guid or string representing a Guid")

#-----------------------------------