Rotate texture, not on a face


#1

Hello guys,

I’m searching for how to set the rotation of the texture before add it to the materials library.
Found some code to rotate texture when apply it on the face, like that: Is it possible to rotate textures using Ruby API? but that’s not what I’ve in mind.

My scenario is:

  • Create a material with a texture with name equal an ID.
  • Set an ‘dynamic_attributes’ to the element with the material id.
  • There is a formula to the material attribute:
    material=my_component!child_component
  • When the child_component receive the ID of the material, he apply this material to himself.

So, I wanna to rotate the texture image before add it to the materials library and put the name of material like ID_horizontal or ID_vertical. Then choose which one I wanna use depending of the orientantion of the component.

Is that possible?

Thanks.


#2

The rotation of a texture is not a property of the material. It is either defined by the UV coordinates on a face, or by the pixel data in the image.

Unfortunately the SketchUp API has no way to edit pixel data (do image manipulation). You would have to write the texture to an image file, run an external (platform-dependend) program and re-import the image. That is slow, requires disk-IO…
If it works for your use case to modify the UV coordinates (= makes changes to the component!, if the user is ok with that), then you could try this:
Iterate over all faces in the component. For each face:

# Get four non-collinear points on the face's plane. 
# If we took them from vertices they could be collinear, so we create points of a square using vector math.
vector_x = face.normal.axes.x
vector_y = face.normal.axes.y
p1 = face.vertices.first.position
p2, p3, p4 = p1 + vector_x, p1 + vector_x + vector_y, p1 + vector_y
# Get a uv helper that will give us the uv coordinates of the material on this face.
uvh = face.get_UVHelper(true, true)
uv1, uv2, uv3, uv4 = [p1, p2, p3, p4].map{ |p|
  uv = uvh.get_front_UVQ(p)
  # Normalize the uvq by dividing by the third q coordinate
  uv.x /= uv.z
  uv.y /= uv.z
  uv.z  = 1
  uv
}
# Rotate the texture by 90° by flipping u and v coordinates (uv is also a Point3d, so literally x and y)
[uv1, uv2, uv3, uv4].each{ |uv|
  uv.x, uv.y = uv.y, 1 - uv.x # You could also do: uv.transform!(transformation)
}
# Re-apply the texture with these new uvs:
pt_array = [ p1, uv1,   p2, uv2,   p3, uv3,   p4, uv4 ]
face.position_material(face.material, pt_array, true)

#3

Ummmm… alright. I’ll have to change my approach of loading and applying material to set it on face not on element.

Thanks for clarify things, very helpful.