# Ruby script for Texture positioning

**URL:** <https://forums.sketchup.com/t/ruby-script-for-texture-positioning/322437>\
**Category:** Ruby API\
**Created:** [April 7, 2025, 7:35pm UTC](https://forums.sketchup.com/t/ruby-script-for-texture-positioning/322437 "2025-04-07T19:35:42Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![evgeny27](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/evgeny27/32/243558_2.png) [@evgeny27](https://forums.sketchup.com/u/evgeny27)\
**Post date:** [April 7, 2025, 7:35pm UTC](https://forums.sketchup.com/t/ruby-script-for-texture-positioning/322437/1 "2025-04-07T19:35:42Z")

</div>

Hey everyone,

I’m trying to write a simple Ruby script that does the following:

- Takes a material named `"TestTexture"` from the model
- Applies it to a face I select
- Aligns and stretches the texture so it fits **exactly** to the face’s **bounding rectangle**
- Starts from the lower-left corner, aligned with the face orientation

* * *

### What I’ve already tried:

- Using `face.position_material(material, pt0, pt1, pt2)` with 3 valid `Point3d`
- Ensuring the points are **not collinear** , and lie **within the face plane**
- Using clean bounding box points (`face.bounds.min`) and offsetting by axes
- Also tried projecting from face center using `face.normal`, `xaxis`, `yaxis`
- Even tried using 8-argument version of `position_material` (with UVs) — which isn’t supported
- Attempted to work with `face.uv_set` — turns out not exposed in Ruby API
- Also tried using `UVHelper` to assist with coordinate mapping

No matter what I try, `position_material` almost always throws this error:

```auto
ArgumentError: Cannot convert argument to Geom::Vector3d

```

Any ideas or sample code would be a huge help 🙏  
Thanks in advance!

---

<div class="post-metadata">

**Author:** ![DanRathbun](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/danrathbun/32/500_2.png) [@DanRathbun](https://forums.sketchup.com/u/DanRathbun)\
**Post date:** [April 7, 2025, 8:12pm UTC](https://forums.sketchup.com/t/ruby-script-for-texture-positioning/322437/2 "2025-04-07T20:12:17Z")

</div>

> [@evgeny27](#):
>
> Starts from the lower-left corner, aligned with the face orientation

I believe that the UV coordinates start from the top left corner.

In my testing it appears that the documentation is lacking. The UV coordinates in `face.position_material` are scale factors between `0.0` and `1,0`.

See these other topics:

- [Generate clickable images and assign functions to it](https://forums.sketchup.com/t/generate-clickable-images-and-assign-functions-to-it/264192)

- [How to rotate a texure following the bigger face side?](https://forums.sketchup.com/t/how-to-rotate-a-texure-following-the-bigger-face-side/314749/)

> [@evgeny27](#):
>
> Even tried using 8-argument version of `position_material` (with UVs) — which isn’t supported

It isn’t? … Is an exception raised?

> [@evgeny27](#):
>
> No matter what I try, `position_material` almost always throws this error:
> 
> ```auto
> ArgumentError: Cannot convert argument to Geom::Vector3d
> 
> ```

We cannot help much without a test model file and a minimal test script demonstrating the issue."

---

<div class="post-metadata">

**Author:** ![evgeny27](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/evgeny27/32/243558_2.png) [@evgeny27](https://forums.sketchup.com/u/evgeny27)\
**Post date:** [April 9, 2025, 7:41pm UTC](https://forums.sketchup.com/t/ruby-script-for-texture-positioning/322437/3 "2025-04-09T19:41:38Z")

</div>

> [@DanRathbun](#):
>
> I believe that the UV coordinates start from the top left corner.
> 
> In my testing it appears that the documentation is lacking. The UV coordinates in `face.position_material` are scale factors between `0.0` and `1,0`.

OMG!  
After years of positioning textures manually (where the red pin always marked the origin at the lower-left corner), I never even considered that position\_material’s UV mapping starts from the top-left.

Thank you for pointing that out!

---

<div class="post-metadata">

**Author:** ![DanRathbun](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/danrathbun/32/500_2.png) [@DanRathbun](https://forums.sketchup.com/u/DanRathbun)\
**Post date:** [April 9, 2025, 9:14pm UTC](https://forums.sketchup.com/t/ruby-script-for-texture-positioning/322437/4 "2025-04-09T21:14:49Z")

</div>

> [@evgeny27](#):
>
> I never even considered that position\_material’s UV mapping starts from the top-left.

That is what I **thought** from testing. But I am not so sure now.

The API documentation is not absolutely clear.

What has me questioning it now, is [`Sketchup::ImageRep#color_at_uv()`](https://ruby.sketchup.com/Sketchup/ImageRep.html#color_at_uv-instance_method) which says:

> The [#color\_at\_uv](https://ruby.sketchup.com/Sketchup/ImageRep.html#color_at_uv-instance_method) method returns a color corresponding to the UV texture coordinates. **0.0, 0.0 maps to the bottom left and 1.0, 1.0 to the top right of the image**.

(_Emboldening by me_.)

Since an `ImageRep` is the internal representation of material textures, this may be a good “clue”.

Also, look at [`Geom::PolygonMesh#set_uv()`](https://ruby.sketchup.com/Geom/PolygonMesh.html#set_uv-instance_method)and it’s example snippet.

The API docs could use a little primer of UVs and SketchUp geometry in the [**Files**](https://ruby.sketchup.com/file_list.html) section.

* * *

I think @thomthom has a UV helper / inspection utility that may help in development.

- [UV Toolkit² | SketchUp Extension Warehouse](https://extensions.sketchup.com/extension/b3855845-ff9d-46d3-89cd-42830dcc5f74/uv-toolkit)

---

<div class="post-metadata">

**Author:** ![thomthom](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/thomthom/32/12606_2.png) [@thomthom](https://forums.sketchup.com/u/thomthom)\
**Post date:** [May 8, 2025, 7:11pm UTC](https://forums.sketchup.com/t/ruby-script-for-texture-positioning/322437/5 "2025-05-08T19:11:30Z")

</div>

> [@evgeny27](#):
>
> face.position\_material(material, pt0, pt1, pt2)

The points given should be pairs of world and UV - from 1 to 4 pairs depending on what you need to control the position, orientation, scale, shear and perspective projection.

To pin a texture to a face:

```auto
points = [
  Geom::Point3d.new(0, 0, 1),
  Geom::Point3d.new(9, 0, 1),
  Geom::Point3d.new(9, 9, 1),
  Geom::Point3d.new(0, 9, 1),
]
face = entities.add_face(points)

uvs = [
  Geom::Point3d.new(0, 0),
  Geom::Point3d.new(1, 0),
  Geom::Point3d.new(1, 1),
  Geom::Point3d.new(0, 1),
]

mapping = points.zip(uvs)
# Mapping then looks like this:
[
  Geom::Point3d.new(0, 0, 1), # World
  Geom::Point3d.new(0, 0), # UV

  Geom::Point3d.new(9, 0, 1), # World
  Geom::Point3d.new(1, 0), # UV

  Geom::Point3d.new(9, 9, 1), # World
  Geom::Point3d.new(1, 1), # UV

  Geom::Point3d.new(0, 9, 1), # World
  Geom::Point3d.new(0, 1), # UV
]

face.position_material(material, mapping, true)

```
