Code improvements

Please help me to fix and improve the code.
On the sketchucation forum I found the code Help please. How to get transformation for the face • sketchUcation • 1
With the help of AI, I was able to refine it a bit for my needs. I added display information about the name of the object and its dimensions. But then I encountered the problem of incorrect display of object sizes if they are rotated relative to the global axes (shown on the screen). Please help me correct the actual size calculation.
The second thing I would like to fix is the selection of the whole object (group/component) instead of just the faces.

Here is the code:

Підсумок
class FaceHighlighterTool
  def initialize
    @ip = Sketchup::InputPoint.new
    @triplets = []
    @edge_points = []
    @hovered_face = nil
    @hovered_face_tra = nil
    @face_color = Sketchup::Color.new(0,40,255,80)
    @edge_color = Sketchup::Color.new(0,0,255,255)
    @edge_width = 3
  end

  def deactivate(view)
    @hovered_face = nil
    view.invalidate
  end

  def onMouseMove(flags, x, y, view)
    @ip.pick(view, x, y)
    face = @ip.face
    if face.nil?
      if @hovered_face
        @hovered_face = nil
        view.invalidate
      end
      return
    end
    if face != @hovered_face
      @hovered_face = face
      @hovered_face_tra = @ip.transformation
      # In order to draw a face with holes, we must draw its mesh
      mesh = face.mesh
      polygons_size = mesh.count_polygons
      @triplets = Array.new(polygons_size)
      for i in 0...polygons_size
        # Obtain one of the triangles making up the face
        triplet = mesh.polygon_points_at(i+1)
        # Transform to global space
        triplet.each { |pt| pt.transform!(@hovered_face_tra) }
        # Store for drawing
        @triplets[i] = triplet
      end
      # Get all edges for drawing a border
      @edge_points.clear
      face.edges.each { |edge|
        @edge_points << edge.start.position
        @edge_points << edge.end.position
      }
      # Transform all edge points to global space
      @edge_points.each { |point| point.transform!(@hovered_face_tra) }
      # Trigger the drawing
      view.invalidate
    end

    @in_path = face ? face.parent.instances : nil
    if @in_path && @in_path.first.is_a?(Sketchup::ComponentInstance)
      @ttip = @in_path.first.name
    else
      @ttip = nil
    end
  end

  def draw(view)
    return unless @hovered_face
    view.drawing_color = @face_color
    @triplets.each { |triplet|
      view.draw(GL_POLYGON, triplet)
    }
    view.drawing_color = @edge_color
    view.line_width = @edge_width
    view.line_stipple = ''
    view.draw(GL_LINES, @edge_points)

    view.tooltip = @ttip if @ttip

    if @in_path
      entity = @in_path.first
      bounds = entity.bounds
      dimensions = [bounds.width, bounds.height, bounds.depth].sort

      length = dimensions.last
      width = dimensions[1]
      thickness = dimensions.first

      text = "Name: #{entity.name}\nLength: #{length}\nWidth: #{width}\nThickness: #{thickness}"
      draw_text_with_bigger_font(view, [40, 20], text, 16)
    end
  end

  def draw_text_with_bigger_font(view, position, text, font_size)
    options = {
      color: "black",
      font: "Arial",
      size: font_size,
      bold: true,
      align: TextAlignLeft
    }
    view.draw_text(position, text, options)
  end
end

Sketchup.active_model.select_tool(FaceHighlighterTool.new)
1 Like

Is the object’s boundingbox larger than the selected geometrie? I expect that the problem is caused by you reading the boundingbox dimensions to determine the size. My advice would be to calculate the dimensions based on the Edge points

For the second “problem” you will have to modify the code and base the selection on a Group or Component first. You could then calculate the dimensions based on the geometry present in the object.

@ nnijmeijer thanks for the answer.

I applied this in modified 2 code and it works. now i get the correct dimensions.

At the same link there is a code that could satisfy the second need. But it does not work correctly for me (see picture).

I tried to change this second code as well. The problem here is incorrect Highlight Too.
I’m already completely confused)
Here is my 2nd code:

Підсумок
class BoundsHighlighterTool
  def initialize
    @ip = Sketchup::InputPoint.new
    @hovered_inst = nil
    @global_parent_tra = nil
    @global_bb = nil
    @labb_global_faces = [] # Faces for the local axes aligned bounding box.
    @gabb_global_faces = [] # Faces for the global axes aligned bounding box.
    @labb_global_edges = []
    @gabb_global_edges = []
    @labb_face_color = Sketchup::Color.new(255,40,0,80)
    @gabb_face_color = Sketchup::Color.new(0,40,255,80)
    @labb_edge_color = Sketchup::Color.new(255,0,0,255)
    @gabb_edge_color = Sketchup::Color.new(0,0,255,255)
    @edge_width = 3
  end

  def deactivate(view)
    reset(view)
  end

  def onMouseMove(flags, x, y, view)
    @ip.pick(view, x, y)
    ip_path = @ip.instance_path
    if ip_path.empty?
      reset(view)
      return
    end
    inst = nil
    gptra = nil
    ip_path.each { |ent|
      break if !ent.is_a?(Sketchup::Group) && !ent.is_a?(Sketchup::ComponentInstance)
      if gptra
        gptra = gptra * inst.transformation
      elsif inst
        gptra = inst.transformation
      end
      inst = ent
    }
    unless inst
      reset(view)
      return
    end
    return if inst == @hovered_inst
    @hovered_inst = inst
    @global_parent_tra = gptra
    local_bb = @hovered_inst.bounds
    # Obtain corners of local axes aligned bounding box in global space
    lagc = []
    for i in 0..7
      lagc << local_bb.corner(i)
    end
    if @global_parent_tra
      lagc.each { |point| point.transform!(@global_parent_tra) }
    end
    @labb_global_faces = [
      [lagc[0], lagc[2], lagc[3], lagc[1]],
      [lagc[4], lagc[6], lagc[7], lagc[5]],
      [lagc[1], lagc[0], lagc[4], lagc[5]],
      [lagc[2], lagc[3], lagc[7], lagc[6]],
      [lagc[0], lagc[2], lagc[6], lagc[4]],
      [lagc[3], lagc[1], lagc[5], lagc[7]]
    ]
    @labb_global_edges = [
      lagc[0], lagc[2],
      lagc[2], lagc[6],
      lagc[6], lagc[4],
      lagc[4], lagc[0],
      lagc[3], lagc[1],
      lagc[1], lagc[5],
      lagc[5], lagc[7],
      lagc[7], lagc[3],
      lagc[0], lagc[1],
      lagc[2], lagc[3],
      lagc[4], lagc[5],
      lagc[6], lagc[7]
    ]
    # Create global axes aligned bounding box
    @global_bb = Geom::BoundingBox.new()
    @global_bb.add(lagc)
    # Obtain corners of global axes aligned bounding box in global space
    gagc = []
    for i in 0..7
      gagc << @global_bb.corner(i)
    end
    @gabb_global_faces = [
      [gagc[0], gagc[2], gagc[3], gagc[1]],
      [gagc[4], gagc[6], gagc[7], gagc[5]],
      [gagc[1], gagc[0], gagc[4], gagc[5]],
      [gagc[2], gagc[3], gagc[7], gagc[6]],
      [gagc[0], gagc[2], gagc[6], gagc[4]],
      [gagc[3], gagc[1], gagc[5], gagc[7]]
    ]
    @gabb_global_edges = [
      gagc[0], gagc[2],
      gagc[2], gagc[6],
      gagc[6], gagc[4],
      gagc[4], gagc[0],
      gagc[3], gagc[1],
      gagc[1], gagc[5],
      gagc[5], gagc[7],
      gagc[7], gagc[3],
      gagc[0], gagc[1],
      gagc[2], gagc[3],
      gagc[4], gagc[5],
      gagc[6], gagc[7]
    ]
    view.invalidate
  end

  def draw(view)
    return unless @hovered_inst
    # Draw local axes aligned global bounding box
    view.drawing_color = @labb_face_color
    @labb_global_faces.each { |face|
      view.draw(GL_POLYGON, face)
    }
    view.drawing_color = @labb_edge_color
    view.line_width = @edge_width
    view.line_stipple = ''
    view.draw(GL_LINES, @labb_global_edges)
    # Draw global axes aligned global bounding box
    view.drawing_color = @gabb_face_color
    @gabb_global_faces.each { |face|
      view.draw(GL_POLYGON, face)
    }
    view.drawing_color = @gabb_edge_color
    view.line_width = @edge_width
    view.line_stipple = ''
    view.draw(GL_LINES, @gabb_global_edges)

    if @hovered_inst.is_a?(Sketchup::Group) || @hovered_inst.is_a?(Sketchup::ComponentInstance)
      entity = @hovered_inst
      edges = entity.definition.entities.select { |e| e.is_a?(Sketchup::Edge) }
      points = edges.flat_map { |e| [e.start.position, e.end.position] }

      min_x, max_x = points.minmax_by { |p| p.x }.map(&:x)
      min_y, max_y = points.minmax_by { |p| p.y }.map(&:y)
      min_z, max_z = points.minmax_by { |p| p.z }.map(&:z)

      length = (max_x - min_x) * 25.4
      width = (max_y - min_y) * 25.4
      thickness = (max_z - min_z) * 25.4

      text = "Name: #{entity.name}\nLength: #{length.round(2)} mm\nWidth: #{width.round(2)} mm\nThickness: #{thickness.round(2)} mm"
      draw_text_with_bigger_font(view, [40, 20], text, 16)
    end
  end

  def reset(view)
    return false unless @hovered_inst
    @hovered_inst = nil
    @global_parent_tra = nil
    @global_bb = nil
    @labb_global_faces.clear
    @gabb_global_faces.clear
    @labb_global_edges.clear
    @gabb_global_edges.clear
    view.invalidate
    return true
  end

  def draw_text_with_bigger_font(view, position, text, font_size)
    options = {
      color: "black",
      font: "Arial",
      size: font_size,
      bold: true,
      align: TextAlignLeft
    }
    view.draw_text(position, text, options)
  end
end

Sketchup.active_model.select_tool(BoundsHighlighterTool.new)

I have postponed the problem of highlighting objects for now because I have a problem with calculating the dimensions.
First, the code was written, which uses the method of calculating the dimensions of the object by the points of the edges (thanks for the tip). And this method works well with objects rotated relative to global axes.
Here is the code.

this code calculates dimensions correctly in rotated relative to global axes, but incorrectly in scaled objects
class TestTool
  def initialize
    @ip = Sketchup::InputPoint.new
    @hovered_inst = nil
  end
  
  def onMouseMove(flags, x, y, view)
    @ip.pick(view, x, y)
    @ph = view.pick_helper
    @in_path = @ip.face ? @ip.face.parent.instances : nil
    @hovered_inst = @in_path&.first if @in_path
    view.invalidate
  end

  def draw(view)
    @ip.draw(view) if @ip.valid?
    view.draw_points(@ip.position, 40, 5, "red") if @ip.valid?
    view.tooltip = @hovered_inst&.name
    if @hovered_inst.is_a?(Sketchup::Group) || @hovered_inst.is_a?(Sketchup::ComponentInstance)
      entity = @hovered_inst
      edges = entity.definition.entities.select { |e| e.is_a?(Sketchup::Edge) }
      points = edges.flat_map { |e| [e.start.position, e.end.position] }

      min_x, max_x = points.minmax_by { |p| p.x }.map(&:x)
      min_y, max_y = points.minmax_by { |p| p.y }.map(&:y)
      min_z, max_z = points.minmax_by { |p| p.z }.map(&:z)

      length = (max_x - min_x) * 25.4
      width = (max_y - min_y) * 25.4
      thickness = (max_z - min_z) * 25.4

      dimensions = [length, width, thickness].sort

      length = dimensions.last
      width = dimensions[1]
      thickness = dimensions.first

      area = (length * width / 1000000).round(2)

      text = "Ім'я: #{entity.name}\nДовжина: #{length.round(1)} мм\nШирина: #{width.round(1)} мм\nТовщина: #{thickness.round(1)} мм\nПлоща: #{area} м.кв."
      draw_text_with_bigger_font(view, [20, 20], text, 16)
    end
  end

  def draw_text_with_bigger_font(view, position, text, font_size)
    options = {
      color: "red",
      font: "Arial",
      size: font_size,
      bold: true,
      align: TextAlignLeft
    }
    view.draw_text(position, text, options)
  end
end

Sketchup.active_model.select_tool(TestTool.new)

But then I ran into a bug and found that it was calculating the dimensions of the scaled object incorrectly. I tried to fix it in the code.
Here is the code.

This code correctly defines dimensions in scaled groups, but incorrectly in rotated relative to global axes
### In the updated code, a new transform_point method was added, which applies the transformation matrix of the object to the specified points.
### This method is used to transform the vertex coordinates of the edges before dimensioning.

class TestTool
  def initialize
    @ip = Sketchup::InputPoint.new
    @hovered_inst = nil
  end
  
  def onMouseMove(flags, x, y, view)
    @ip.pick(view, x, y)
    @ph = view.pick_helper
    @in_path = @ip.face ? @ip.face.parent.instances : nil
    @hovered_inst = @in_path&.first if @in_path
    view.invalidate
  end

  def draw(view)
    @ip.draw(view) if @ip.valid?
    view.draw_points(@ip.position, 40, 5, "red") if @ip.valid?
    view.tooltip = @hovered_inst&.name
    if @hovered_inst.is_a?(Sketchup::Group) || @hovered_inst.is_a?(Sketchup::ComponentInstance)
      entity = @hovered_inst
      edges = entity.definition.entities.select { |e| e.is_a?(Sketchup::Edge) }
      transformed_points = edges.flat_map { |e| transform_point(entity.transformation, e.start.position, e.end.position) }

      min_x, max_x = transformed_points.minmax_by { |p| p.x }.map(&:x)
      min_y, max_y = transformed_points.minmax_by { |p| p.y }.map(&:y)
      min_z, max_z = transformed_points.minmax_by { |p| p.z }.map(&:z)

      length = (max_x - min_x) * 25.4
      width = (max_y - min_y) * 25.4
      thickness = (max_z - min_z) * 25.4

      dimensions = [length, width, thickness].sort

      length = dimensions.last
      width = dimensions[1]
      thickness = dimensions.first

      area = (length * width / 1000000).round(2)

      text = "Ім'я: #{entity.name}\nДовжина: #{length.round(1)} мм\nШирина: #{width.round(1)} мм\nТовщина: #{thickness.round(1)} мм\nПлоща: #{area} м.кв."
      draw_text_with_bigger_font(view, [20, 20], text, 16)
    end
  end

  def transform_point(transformation, *points)
    points.map { |pt| transformation * pt }
  end

  def draw_text_with_bigger_font(view, position, text, font_size)
    options = {
      color: "red",
      font: "Arial",
      size: font_size,
      bold: true,
      align: TextAlignLeft
    }
    view.draw_text(position, text, options)
  end
end

Sketchup.active_model.select_tool(TestTool.new)

I try to combine these two methods, but nothing works). What am I doing wrong?
I will be very grateful for tips.

Maybe it helps Changing component boundingbox rotation axes
It worked for me