Drawingelement#visible? seems to return inconsistent results

If a simple SketchUp model is built with 2 groups of geometry, and tag a is assigned one and tag b to the other, and if the following code is run:

Sketchup.active_model.entities.select(&:visible?)

An array of two Groups is returned (expected).

If the visibility one of the groups is turned off in Outliner, an array of one group is returned (expected).

If the visibility of one of the tags is turned off in Tags, an array of two groups is returned (unexpected). Note that turning of the visibility of the tag in Tags also turns off the visibility of the corresponding group in Outliner. Can someone help me with an explanation?

Visible test.skp (72.7 KB)

No.
There, in the Outliner the coresponding group is just grayed out. If you look closer, you do have same :eye: symbol as before but not black but gray.
gr_l_vis

If you turning off the associated tag (layer) you have to look for the visibility of the layer.

Sketchup.active_model.entities.select{|ent| ent.layer.visible?}

or examine both

Sketchup.active_model.entities.select{|ent| 
  ent.visible? && ent.layer.visible?
}

In other words, the following code …

… is selecting Drawingelement objects based upon the inverse return value of their boolean hidden property and nothing more. (The visible? method documentation description is a bit misleading.)

Whether you actually see elements in the model view also must take into account whether their assigned layer (tag) or any of this layer’s ancestor layer folders are set to be visible. Also, if any of an element’s ancestral geometric collections that it is contained within or the layers they use (including layer folders) are set hidden, then the element also will not be shown (even though the element’s individual visible property is true.)

There are also 2 rendering options that control whether you see hidden objects (groups and component instances) or hidden geometry (primitives like faces and edges) as dotted outlines.

So you need to go about this task in another way. See:

:thinking:
Continuing Dan’s line of thought, we can go even deeper into the complexity of visibility …
E.g. if (or do) we want to consider whether the object in question is visible on other than currently selected scene (?)

The #get_drawingelement_visibility method is used to get the visibility of a drawing element on a particular page.

The #layers method retrieves layers that don’t use their default visibility on this page.

The #layer_folders method retrieves the hidden layer folders associated with a page.

etc… :blush:

I have added a tag folder to my simple example model. I understand that I would need to traverse the entire graph and provide a longer instance_path array for a more complex model, but in this case, if the following code is run:

mod = Sketchup.active_model
mod.entities.select{|ent|
  p ent
  mod.drawing_element_visible?([ent])
}

an error is returned:

=> 
#<Sketchup::Group:0x00000262a0154668>
"Leaf must be a type of Sketchup::Drawingelement (Line 4)"

Is the leaf not the last (and in this case only) element in the instance_path array? And is a Group not a Drawingelement?

Visible test.skp (71.4 KB)

You are right. The example in the #drawing_element_visible? method documentation resulting the same error.

It seams eider the documentation is erroneous or the method itself cannot handle the group or component instance in the root of the model.

As I see, the method is looking for the leaf of the InstancePath, however the InstancePath of the root instance does not contains the optional leaf entity…

Yes.

You have apparently found a bug. In testing on both 2021 and 2022 I cannot form a valid Sketchup::InstancePath object that has a group as it’s leaf. This also effects passing a coercible array to the method in question.

There are already a number of issues open with this method and the Sketchup::InstancePath class in the API Bug Tracker.
Please file a bug report with a link back to this topic.

I was going to mention this in the bug report but I don’t get the same behavior (on 2022):

mod = Sketchup.active_model
group = mod.entities.add_group
path = Sketchup::InstancePath.new([group])
path.valid?

returns true

# valid?

An instance path is valid if it has at least one element and consist of groups and instances with exception of the leaf which can be any entity.
This method doesn’t check if the path can actually be looked up in the model.

I think the this method will not give a right information here. (or also erroneous )

The issue is that the #leaf instance_method returns nil

mod = Sketchup.active_model
group = mod.entities.add_group
path = Sketchup::InstancePath.new([group])
path.leaf
=> nil

Beside that this is not documented, according to the error message above, the #drawing_element_visible? method is “looking for” a leaf.
But, it seams, that proper InstancePath can not be constructed (at least for this method) if the group/instance is on a root of the model.

BTW. Dan already reported this issue in other aspect: Sketchup::Model#drawing_element_visible? TypeError message is not quite correct · Issue #570 · SketchUp/api-issue-tracker · GitHub

Yes, but you see the response that I got ?

Yes, I saw it. :disappointed_relieved:
Hope this time we get more serious attention.

I wrote a post for a similar problem but not in the right discussion

I also have a problem with whether an entity is visible or not in a scene (page)

to find out, it seems that there are two methods for this, Sketchup::active_model.pages.selected_page.hidden_entitie and Sketchup::active_model.pages.selected_page.get_drawingelement_visibility(entity)

The hidden_entities method only gives entities at the root, so the “planches toit” group is not in the table of hidden entities, and get_drawingelement_visibility for the component “planche toit terrasse” return “true”

So, we are forced to go through the entire tree of entities to find out if an element is visible or not.

but it’s very heavy to do this in a loop to test the visibility of each entity

One solution I found was to rebuild an array of all hidden entities in the active page (only group and component) and use a function that use this array to know if an entity is visible or not

here the code to rebuild $hiddenIdentities array

def getAllHiddenEntities
  $hiddenEntities = []
  listHiddenEntities(Sketchup.active_model.entities)  
end

def listHiddenEntities(entities, visible = true)
  entities.each { | ent | 
    if ent.is_a?(Sketchup::ComponentInstance) || ent.is_a?(Sketchup::Group)
      if !ent.visible? || !visible
        setHiddenEntity(ent)
      end
    end
    if ent.is_a?(Sketchup::Group)
      listHiddenEntities(ent.entities, ent.visible? & visible)
    end
  }  
end

def setHiddenEntity (entite)
  if !$hiddenEntities.include?(entite)
      $hiddenEntities.push(entite)
  end
end

and when you want to know if a group or a component is visible or not: (sorry is not very elegant, i’m beginner in ruby)

def entityActive?(ent) 
  if($hiddenEntities && $hiddenEntities.include?(ent)) 
    res = false
  else
    res = true
  end
  return(res);
end

We cannot test your scenario without a test model. But …

What does Sketchup::Model#drawing_element_visible?(instance_path) return in this scenario for the “planches toit” group and the “planche toit terrasse” component instance?

i have also this error :
Error: #<ArgumentError: Leaf must be a type of Sketchup::Drawingelement>
in this project the the group “comp”
testRuby.skp (293.6 KB)

i get the error with this code

def test(entities, path = [])
  entities.each { | ent | 
    if(ent.is_a?(Sketchup::Drawingelement))
        puts "its a drawing element #{ent.class.to_s} "  # even when it's a Sketchup::group
        vis = ent.model.drawing_element_visible?(path + [ent]) 
    end
    if ent.is_a?(Sketchup::Group)
      test(ent.entities, path + [ent])
    end
  }
end
test(Sketchup.active_model.entities)

it would seem that a sketchup::group is considered as a drawing element ?
puts display : its a drawing element Sketchup::Group []

I don’t know all the subtilities of sketchup yet, I needed to create a material array with for each its list of visible components, so I made a loop starting from the defintionList, its maybe a mistake because with this kind of loop, I couldn’t know the path of a defintion and its entities

The best solution I found was to build a array of hidden elements, and then I can use this array to know the visibility of an element without knowing its path in the hierarchy

I continued to do research to better understand the problem, and with this code (on the project sketchup of my previous post)

def test(entities, path = [])
  entities.each { | ent | 
    if(ent.is_a?(Sketchup::Drawingelement))
      pa = Sketchup::InstancePath.new(path + [ent])
      puts "its a drawing element #{ent.class.to_s} " + getName(ent) + "  valid = #{pa.valid?} leaf = #{pa.leaf.to_s} root = " + getName(pa.root)  # even when it's a Sketchup::group
      #vis = ent.model.drawing_element_visible?(pa) 
    end
    if ent.is_a?(Sketchup::Group) 
      test(ent.entities, path + [ent])
    end
    if ent.is_a?(Sketchup::ComponentInstance) 
      test(ent.definition.entities, path + [ent])
    end
  }
end

def getName(entity, id = "")
  cm = entity.class.to_s.gsub("Sketchup::", "")
  if(cm != "Group" && entity.respond_to?(:definition))
      entity = entity.definition
  end
  if(entity.respond_to?(:name) && entity.name)
      name = "#{cm}_#{entity.name}"
  else
      if(entity.respond_to?(:entityID) && entity.entityID != nil)
          name = "#{cm}_entityID_#{entity.entityID}"
      else 
          name = "#{cm}_id_#{id}"
      end
  end
  return(name)
end

I get this result:

test(Sketchup.active_model.entities)
its a drawing element Sketchup::Group Group_comp  valid = true leaf =  root = Group_comp
its a drawing element Sketchup::Group Group_comp 1 2  valid = true leaf =  root = Group_comp
its a drawing element Sketchup::ComponentInstance ComponentInstance_comp 2  valid = true leaf =  root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_144  valid = true leaf = #<Sketchup::Edge:0x000000001dc59eb0> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_145  valid = true leaf = #<Sketchup::Edge:0x000000001dc59438> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_146  valid = true leaf = #<Sketchup::Edge:0x000000001dc58bc8> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_147  valid = true leaf = #<Sketchup::Edge:0x000000001dc58128> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_148  valid = true leaf = #<Sketchup::Edge:0x000000001dc57598> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_149  valid = true leaf = #<Sketchup::Edge:0x000000001dc56710> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_150  valid = true leaf = #<Sketchup::Edge:0x000000001dc551d0> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_151  valid = true leaf = #<Sketchup::Edge:0x000000001dc54348> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_152  valid = true leaf = #<Sketchup::Edge:0x000000001dc50db0> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_153  valid = true leaf = #<Sketchup::Edge:0x000000001dc50220> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_154  valid = true leaf = #<Sketchup::Edge:0x000000001dc9df48> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_155  valid = true leaf = #<Sketchup::Edge:0x000000001dc9ca08> root = Group_comp
its a drawing element Sketchup::Face Face_entityID_156  valid = true leaf = #<Sketchup::Face:0x000000001dc9ba18> root = Group_comp
its a drawing element Sketchup::Face Face_entityID_162  valid = true leaf = #<Sketchup::Face:0x000000001dc989a8> root = Group_comp
its a drawing element Sketchup::Face Face_entityID_168  valid = true leaf = #<Sketchup::Face:0x000000001dc97c38> root = Group_comp
its a drawing element Sketchup::Face Face_entityID_174  valid = true leaf = #<Sketchup::Face:0x000000001dc96cc0> root = Group_comp
its a drawing element Sketchup::Face Face_entityID_180  valid = true leaf = #<Sketchup::Face:0x000000001dc95e38> root = Group_comp
its a drawing element Sketchup::Face Face_entityID_186  valid = true leaf = #<Sketchup::Face:0x000000001dc95320> root = Group_comp
its a drawing element Sketchup::ComponentInstance ComponentInstance_comp 1  valid = true leaf =  root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_76  valid = true leaf = #<Sketchup::Edge:0x000000001dc93d68> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_77  valid = true leaf = #<Sketchup::Edge:0x000000001dc934d0> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_78  valid = true leaf = #<Sketchup::Edge:0x000000001dc92e90> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_79  valid = true leaf = #<Sketchup::Edge:0x000000001dc92558> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_80  valid = true leaf = #<Sketchup::Edge:0x000000001dc91e00> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_81  valid = true leaf = #<Sketchup::Edge:0x000000001dc918d8> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_82  valid = true leaf = #<Sketchup::Edge:0x000000001dc91248> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_83  valid = true leaf = #<Sketchup::Edge:0x000000001dc90848> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_84  valid = true leaf = #<Sketchup::Edge:0x000000001dc90050> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_85  valid = true leaf = #<Sketchup::Edge:0x000000001da1e100> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_86  valid = true leaf = #<Sketchup::Edge:0x000000001da1c878> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_87  valid = true leaf = #<Sketchup::Edge:0x000000001da1abe0> root = Group_comp
its a drawing element Sketchup::Face Face_entityID_88  valid = true leaf = #<Sketchup::Face:0x000000001da18930> root = Group_comp
its a drawing element Sketchup::Face Face_entityID_94  valid = true leaf = #<Sketchup::Face:0x000000001da16fb8> root = Group_comp
its a drawing element Sketchup::Face Face_entityID_100  valid = true leaf = #<Sketchup::Face:0x000000001da16720> root = Group_comp
its a drawing element Sketchup::Face Face_entityID_106  valid = true leaf = #<Sketchup::Face:0x000000001da16158> root = Group_comp
its a drawing element Sketchup::Face Face_entityID_112  valid = true leaf = #<Sketchup::Face:0x000000001da15960> root = Group_comp
its a drawing element Sketchup::Face Face_entityID_118  valid = true leaf = #<Sketchup::Face:0x000000001da15230> root = Group_comp
its a drawing element Sketchup::Group Group_comp 3 4  valid = true leaf =  root = Group_comp
its a drawing element Sketchup::ComponentInstance ComponentInstance_comp 3  valid = true leaf =  root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_212  valid = true leaf = #<Sketchup::Edge:0x000000001da13f70> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_213  valid = true leaf = #<Sketchup::Edge:0x000000001da138e0> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_214  valid = true leaf = #<Sketchup::Edge:0x000000001da120f8> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_215  valid = true leaf = #<Sketchup::Edge:0x000000001da11a90> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_216  valid = true leaf = #<Sketchup::Edge:0x000000001da111f8> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_217  valid = true leaf = #<Sketchup::Edge:0x000000001da106e0> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_218  valid = true leaf = #<Sketchup::Edge:0x000000001d9cfd70> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_219  valid = true leaf = #<Sketchup::Edge:0x000000001d9cf528> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_220  valid = true leaf = #<Sketchup::Edge:0x000000001d9ceb50> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_221  valid = true leaf = #<Sketchup::Edge:0x000000001d9cdf98> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_222  valid = true leaf = #<Sketchup::Edge:0x000000001d9cd688> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_223  valid = true leaf = #<Sketchup::Edge:0x000000001d9ccdf0> root = Group_comp
its a drawing element Sketchup::Face Face_entityID_224  valid = true leaf = #<Sketchup::Face:0x000000001d9cc648> root = Group_comp
its a drawing element Sketchup::Face Face_entityID_230  valid = true leaf = #<Sketchup::Face:0x000000001d9cbe78> root = Group_comp
its a drawing element Sketchup::Face Face_entityID_236  valid = true leaf = #<Sketchup::Face:0x000000001d9cb3b0> root = Group_comp
its a drawing element Sketchup::Face Face_entityID_242  valid = true leaf = #<Sketchup::Face:0x000000001d9ca640> root = Group_comp
its a drawing element Sketchup::Face Face_entityID_248  valid = true leaf = #<Sketchup::Face:0x000000001d9c8278> root = Group_comp
its a drawing element Sketchup::Face Face_entityID_254  valid = true leaf = #<Sketchup::Face:0x000000001d9c6a18> root = Group_comp
its a drawing element Sketchup::ComponentInstance ComponentInstance_comp 4  valid = true leaf =  root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_280  valid = true leaf = #<Sketchup::Edge:0x000000001d9c4718> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_281  valid = true leaf = #<Sketchup::Edge:0x000000001d9c3638> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_282  valid = true leaf = #<Sketchup::Edge:0x000000001d9c2c38> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_283  valid = true leaf = #<Sketchup::Edge:0x000000001d9c1e28> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_284  valid = true leaf = #<Sketchup::Edge:0x000000001d9c17e8> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_285  valid = true leaf = #<Sketchup::Edge:0x000000001d9c11f8> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_286  valid = true leaf = #<Sketchup::Edge:0x000000001d9c0c08> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_287  valid = true leaf = #<Sketchup::Edge:0x000000001d9c05a0> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_288  valid = true leaf = #<Sketchup::Edge:0x0000000021ddfc90> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_289  valid = true leaf = #<Sketchup::Edge:0x0000000021ddf768> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_290  valid = true leaf = #<Sketchup::Edge:0x0000000021ddf290> root = Group_comp
its a drawing element Sketchup::Edge Edge_entityID_291  valid = true leaf = #<Sketchup::Edge:0x0000000021ddee30> root = Group_comp
its a drawing element Sketchup::Face Face_entityID_292  valid = true leaf = #<Sketchup::Face:0x0000000021dde868> root = Group_comp
its a drawing element Sketchup::Face Face_entityID_298  valid = true leaf = #<Sketchup::Face:0x0000000021dde408> root = Group_comp
its a drawing element Sketchup::Face Face_entityID_304  valid = true leaf = #<Sketchup::Face:0x0000000021dddf30> root = Group_comp
its a drawing element Sketchup::Face Face_entityID_310  valid = true leaf = #<Sketchup::Face:0x0000000021dddad0> root = Group_comp
its a drawing element Sketchup::Face Face_entityID_316  valid = true leaf = #<Sketchup::Face:0x0000000021ddd5f8> root = Group_comp
its a drawing element Sketchup::Face Face_entityID_322  valid = true leaf = #<Sketchup::Face:0x0000000021ddd198> root = Group_comp

leaf method on a instancePath return nil when the last item is a group or a component
that’s probably why we have this error Leaf must be a type of Sketchup::Drawingelement

I reported the error here :

I am sorry. There is an open bug in the API (that I forgot about) …