# Code improvements

**URL:** <https://forums.sketchup.com/t/code-improvements/235356>\
**Category:** Ruby API\
**Created:** [July 12, 2023, 2:20pm UTC](https://forums.sketchup.com/t/code-improvements/235356 "2023-07-12T14:20:57Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![KScher](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/kscher/32/41084_2.png) [@KScher](https://forums.sketchup.com/u/KScher)\
**Post date:** [July 12, 2023, 2:20pm UTC](https://forums.sketchup.com/t/code-improvements/235356/1 "2023-07-12T14:20:57Z")

</div>

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](https://sketchucation.com/forums/viewtopic.php?f=180&t=67058&p=614914&hilit=edges+to+arc#p614914)  
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.

 ![Безіменний](https://global.discourse-cdn.com/sketchup/original/3X/f/2/f2fcea5133c8807948604b0d320562c81a08ff9e.jpeg)

Here is the code:

> **Підсумок**
>
> ```ruby
> 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)
> 
> ```

---

<div class="post-metadata">

**Author:** ![nnijmeijer](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/nnijmeijer/32/66166_2.png) [@nnijmeijer](https://forums.sketchup.com/u/nnijmeijer)\
**Post date:** [July 12, 2023, 5:48pm UTC](https://forums.sketchup.com/t/code-improvements/235356/2 "2023-07-12T17:48:59Z")

</div>

> [@KScher](#):
>
> `dimensions = [bounds.width, bounds.height, bounds.depth].sort`

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

> **[Class: Geom::BoundingBox](https://ruby.sketchup.com/Geom/BoundingBox.html)**
>
> Bounding boxes are three-dimensional boxes (eight corners), aligned with the axes, that surround entities within your model.

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.

> **[Class: Sketchup::Selection](https://ruby.sketchup.com/Sketchup/Selection.html)**
>
> A set of the currently selected entities.

> **[Class: Sketchup::ComponentInstance](https://ruby.sketchup.com/Sketchup/ComponentInstance.html)**
>
> The Sketchup::ComponentInstance class is used to represent component instances of a component definition or components that have been dragged from the Component Browser and placed (thus, instanced) within the Model.

> **[Class: Sketchup::ComponentDefinition](https://ruby.sketchup.com/Sketchup/ComponentDefinition.html)**
>
> The Sketchup::ComponentDefinition class is used to define the contents for a SketchUp component.

> **[Class: Sketchup::Group](https://ruby.sketchup.com/Sketchup/Group.html)**
>
> A Group class contains methods for manipulating groups of entities.

---

<div class="post-metadata">

**Author:** ![KScher](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/kscher/32/41084_2.png) [@KScher](https://forums.sketchup.com/u/KScher)\
**Post date:** [July 12, 2023, 7:13pm UTC](https://forums.sketchup.com/t/code-improvements/235356/3 "2023-07-12T19:13:38Z")

</div>

@ [nnijmeijer](https://forums.sketchup.com/u/nnijmeijer) thanks for the answer.

> [@nnijmeijer](#):
>
> My advice would be to calculate the dimensions based on the Edge points

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

> [@KScher](#):
>
> On the sketchucation forum I found the code [Help please. How to get transformation for the face • sketchUcation • 1](https://sketchucation.com/forums/viewtopic.php?f=180&t=67058&p=614914&hilit=edges+to+arc#p614914)

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

 ![Без імені](https://global.discourse-cdn.com/sketchup/original/3X/a/c/acf3309db697017b8bf9eed08f0619c61624cc9b.jpeg)

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:

> **Підсумок**
>
> ```ruby
> 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)
> 
> ```

---

<div class="post-metadata">

**Author:** ![KScher](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/kscher/32/41084_2.png) [@KScher](https://forums.sketchup.com/u/KScher)\
**Post date:** [July 14, 2023, 10:10am UTC](https://forums.sketchup.com/t/code-improvements/235356/4 "2023-07-14T10:10:47Z")

</div>

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**
>
> ```ruby
> 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**
>
> ```ruby
> ### 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.

---

<div class="post-metadata">

**Author:** ![rtches](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/rtches/32/131827_2.png) [@rtches](https://forums.sketchup.com/u/rtches)\
**Post date:** [July 14, 2023, 12:25pm UTC](https://forums.sketchup.com/t/code-improvements/235356/5 "2023-07-14T12:25:49Z")

</div>

Maybe it helps [Changing component boundingbox rotation axes](https://forums.sketchup.com/t/changing-component-boundingbox-rotation-axes/203485)  
It worked for me
