Group by Layer/Tag

When geometry is imported from an app such as CAD that attaches layers to edges and faces, the result is often a chaotic mess in SketchUp that violates the guidance to apply tags (formerly layers) only to Groups and Components. The temptation is to remove the tags from all edges and faces, but those tags often carry important semantic information about the original model. That information is lost when everything is made untagged.

The code snippet below, when pasted into the Ruby Console, will fix this situation by creating a group for each layer/tag used by a loose edge or face, moving the edge or face into that group, and making the edge or face untagged. The new group then has the original tag attached to it. The code does not probe inside existing groups or components looking for incorrectly tagged edges or faces, as there are already other extensions that handle that.

It is possible that some of the edges or faces with distinct tags may have intersected during the import. Some cleanup may be needed to repair fragmented ones, but it will all be cleanly separated into the tag’s group.

If this proves useful, I could publish it as a plugin command with toolbar, etc. Please let me know if you find it useful.

module SLBPlugins
  module GroupByLayer
    # Examine loose geometry in the model and create a group for each layer/tag
    # used by it.  Assign the tag to the created group and then make each contained
    # entity be untagged.  This won't alter any pre-existing groups or components.
    # In this way, the semantics of the original tagging are preserved without
    # the issues caused by tagging edges or faces.
    # This will fix many models in which the user has employed
    # SketchUp's layers/tags in the wrong way by associating them with loose geometry.
    # A prime offender is from import of a CAD (dwg or dxf) model that used their layers
    # (which is really an issue with the importer rather than the user's own usage).
    # It doesn't do anything about layer usage by nested geometry as there are
    # other methods (e.g. all_to_zero in this module) and plugins (e.g. TIG's)
    # that already do that.  Imported CAD doesn't normally
    # have nested geometry, so it isn't usually a need in that case.
    # Some subsequent cleanup within each group may be needed, as this doesn't
    # try to repair the consequences of geometry intersecting due to misunderstanding
    # of layers.  There may be broken edges and coplanar faces that can now be fixed
    # without damaging things in the other groups.
    # Note: loose geometry that (properly) uses Layer0 is handled the same way
    # as loose geometry that uses other layers.  There will be a new group for it.
    def self.group_by_layer
      # gather up loose edges and faces
      loose_faces = Sketchup.active_model.entities.grep(Sketchup::Face)
      loose_edges = Sketchup.active_model.entities.grep(Sketchup::Edge)
      # retain only edges not used by any face.  Edges needed by a face
      # will be handled along with the face.
      loose_free_edges = loose_edges.delete_if {|edge| !edge.faces.empty?}
      loose_geometry = loose_faces + loose_free_edges
      # Hash with a key for each layer used by loose geometry and value
      # an array of entities that use that layer.  Default initializes a
      # empty array so we can append items.
      loose_by_layer = {|h,k| h[k] = []}
      loose_geometry.each {|entity| loose_by_layer[entity.layer] << entity}
      # create a group for each used layer and put the associated geometry
      # into it.  Because a face must have all its edges in the same context,
      # this will do two things: it will bring the bounding edges of the face
      # into the group even if they weren't using this layer, and it will create
      # a duplicate in the model if the edge is needed to bound a face still there.
      # These new edges in model aren't in the list we built earlier but aren't needed
      # because we captured only faces and free edges, not edges that bound faces.
      Sketchup.active_model.start_operation("Group by layer", true)
      loose_by_layer.keys.each do |layer|
          gp = Sketchup.active_model.entities.add_group(loose_by_layer[layer])
          # use the layer from the original loose entities for the group
          gp.layer = layer
          # and fix the Layer0 association of the ones in the group
          gp.definition.entities.each {|entity| entity.layer = nil}
        rescue => e
          # note: this reports the exception but lets the method
          # continue to process the rest of the layers
          puts e.message
          puts e.backtrace


Thank you, @slbaumgartner!

It will shorten working times considerably, compared to what I showed in the post

The important idea is that when a dwg file is imported, the layers should not be deleted automatically, because useful information is lost.
In fact, layers+geometry from dwg should not be deleted anyway, but grouped in a folder and that’s it.

There used to be one similar, but it’s no longer available…

(I’ll look around to see if I still have it somewhere.)
I found it, but it uses no namespace, and have global variable in it, so I won’t post it here.
This one explodes the existing instances and then groups them by layer… Yours seems better :slight_smile: