How to rotate a texure following the bigger face side?

Hello guys, how may i to rotate a texure throught the face using ruby?
I’m trying to create a script that apply a texture on the face but i wish the texture rotate to follow the bigger side of the face.

What’s the best way to do it?


(texture following the bigger face side)

what i’m trying to do :point_down:

def self.apply_texture_to_faces(entity, material)
  return unless entity.is_a?(Sketchup::Group) || entity.is_a?(Sketchup::ComponentInstance)

  definition = entity.definition
  model = Sketchup.active_model
  model.start_operation('Apply Textures to Internal Faces', true)

  entity.make_unique if entity.is_a?(Sketchup::ComponentInstance)

  definition.entities.grep(Sketchup::Face).each do |face|
    face.material = material

    if material.texture
      # Determinar a maior dimensão da face
      bounds = face.bounds
      width = bounds.width
      height = bounds.height
      longest_edge = width > height ? :x : :y

      # Obter os vértices da face
      vertices = face.outer_loop.vertices.map(&:position)
      sorted_vertices = vertices.sort_by { |v| v.to_a[longest_edge == :x ? 0 : 1] }

      # Definir pontos de referência para a textura
      pt1 = sorted_vertices[0]
      pt2 = sorted_vertices[-1]
      pt3 = sorted_vertices.length > 2 ? sorted_vertices[1] : sorted_vertices[-1]

      uv_helper = face.get_UVHelper(true, true, material.texture)
      uv1 = uv_helper.get_front_UVQ(pt1)
      uv2 = uv_helper.get_front_UVQ(pt2)
      uv3 = uv_helper.get_front_UVQ(pt3)

      face.position_material(material, [pt1, pt2, pt3], [uv1, uv2, uv3], true)
    end
  end

  model.commit_operation
end

I have less experience with position material… but, I believe that the condition here ( after entity.make_unique) is not needed, shuld be used for groups too.

Groups in SketchUp are very similar to components, but can from a user point of view be thought of as unique objects. Copying a group in SketchUp will create a group that shares the same definition. SketchUp implicitly makes group unique when edited from the GUI, and from a user point of view groups could be thought of as always being unique.
To honor this behavior, make sure to call #make_unique before modifying a group through the API.

1 Like

perfect, it’s really helped me to solve other problem that i was having.

1 Like

FYI: You can “rotate” an array of UV values in Ruby using Array#rotate() and
Array#rotate!(). For UV values this means 90 degrees for each rotation of the values.

uvs = [uv1, uv2, uv3]
# Rotate 180 degrees:
uvs.rotate!(2)
uvs.inspect
#=> "[uv3,uv1,uv2]"
1 Like

I’m trying with just one selected face, it show’s the result “Textura Aplicada (that means it’s worked)”
but the result keep the same

my code example:

def apply_aligned_texture
  model = Sketchup.active_model
  selection = model.selection
  materials = model.materials
  active_material = materials.current

  # Check if a single face is selected
  unless selection.length == 1 && selection.first.is_a?(Sketchup::Face)
    puts "Select ONE single face."
    return
  end

  # Check if the active material has a texture
  unless active_material&.texture
    puts "Select a material with a texture."
    return
  end

  face = selection.first
  face.material = active_material

  # Identify the longest edge of the face
  longest_edge = face.edges.max_by(&:length)
  return puts "Error: Could not find a valid edge." unless longest_edge

  pt1 = longest_edge.start.position
  pt2 = longest_edge.end.position
  edge_vector = (pt2 - pt1).normalize

  # Create a third point ensuring it is not collinear
  normal_vector = face.normal
  perpendicular_vector = edge_vector.cross(normal_vector).normalize
  if perpendicular_vector.length == 0
    puts "Error: Collinear vectors, unable to calculate a valid coordinate system."
    return
  end
  pt3 = pt1.offset(perpendicular_vector, 1.m)

  # Create a `UVHelper` to obtain correct UV coordinates
  uv_helper = face.get_UVHelper(true, true)
  uv1 = uv_helper.get_front_UVQ(pt1)
  uv2 = uv_helper.get_front_UVQ(pt2)
  uv3 = uv_helper.get_front_UVQ(pt3)

  # Normalize UVs (prevent distortion)
  def normalize_uv(uv)
    uv.x /= uv.z if uv.z != 0
    uv.y /= uv.z if uv.z != 0
    uv.z = 1
    uv
  end

  uv1 = normalize_uv(uv1)
  uv2 = normalize_uv(uv2)
  uv3 = normalize_uv(uv3)

  # Get the texture dimensions
  texture = active_material.texture
  texture_width = texture.width
  texture_height = texture.height
  texture_aspect_ratio = texture_width.to_f / texture_height

  # Calculate the aspect ratio of the longest edge
  edge_length = longest_edge.length
  perpendicular_length = 1.m # Arbitrary length used for the perpendicular vector
  face_aspect_ratio = edge_length.to_f / perpendicular_length

  # Determine if the texture needs to be rotated
  if (texture_aspect_ratio > 1 && face_aspect_ratio < 1) || (texture_aspect_ratio < 1 && face_aspect_ratio > 1)
    # Rotate UV coordinates by 90 degrees
    uvs = [uv1, uv2, uv3]

    # Swap x and y values to simulate rotation
    uvs.each do |uv|
      uv.x, uv.y = uv.y, uv.x
    end

    # Reorganize UV coordinates to reflect the rotation
    uv1, uv2, uv3 = uvs.rotate(1)
  end

  # Apply the texture correctly to the face
  model.start_operation('Apply Aligned Texture', true)
  begin
    mapping = [pt1, uv1, pt2, uv2, pt3, uv3]
    face.position_material(active_material, mapping, true)
    puts "Texture applied successfully!"
  rescue => e
    puts "Error applying texture: #{e.message}"
  ensure
    model.commit_operation
  end

  # Force viewport update
  model.active_view.invalidate
end

apply_aligned_texture

Post code correctly in the forum and please edit your previous post.


Also, Ruby is an English coding language. Most here do not speak or read Portuguese code commants.

1 Like

corrected.

You are still not using:
```ruby

This is calling 2 methods. You can call one method thus:

selection.single_object?

Do not assume that the user has the Ruby Console open. Instead use:

    UI.messagebox("Select ONE single face.")

Why do both ?

1 Like

I’m trying to solve the texture position on the face using the console. After do that, i’ll increase this feature on my complete code

the goal is try to apply texture following the bigger side of the face. the bigger leght of the texture aligned with the bigger lenght of the face.