TexTools is a UV and Texture tool set for 3dsMax created several years ago. This open repository will port in time several of the UV tools to Blender in python. http://renderhjs.net/textools/blender
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

145 lines
4.3 KiB

import bpy
import bmesh
import operator
import math
from mathutils import Vector
from collections import defaultdict
from math import pi
from . import utilities_uv
class op(bpy.types.Operator):
bl_idname = "uv.textools_island_align_edge"
bl_label = "Align Island by Edge"
bl_description = "Align the island by selected edge"
bl_options = {'REGISTER', 'UNDO'}
def poll(cls, context):
# Only in UV editor mode
if bpy.context.area.type != 'IMAGE_EDITOR':
return False
if not bpy.context.active_object:
return False
if bpy.context.active_object.type != 'MESH':
return False
# Only in Edit mode
if bpy.context.active_object.mode != 'EDIT':
return False
if bpy.context.scene.tool_settings.use_uv_select_sync:
return False
# Requires UV map
if not bpy.context.object.data.uv_layers:
return False
# Requires UV Edge select mode
if bpy.context.scene.tool_settings.uv_select_mode != 'EDGE':
return False
return True
def execute(self, context):
# Store selection
# Restore selection
return {'FINISHED'}
def main(context):
print("Executing operator_island_align_edge")
bm = bmesh.from_edit_mesh(bpy.context.active_object.data)
uv_layers = bm.loops.layers.uv.verify()
faces_selected = []
for face in bm.faces:
if face.select:
for loop in face.loops:
if loop[uv_layers].select:
print("faces_selected: "+str(len(faces_selected)))
# Collect 2 uv verts for each island
face_uvs = {}
for face in faces_selected:
uvs = []
for loop in face.loops:
if loop[uv_layers].select:
if len(uvs) >= 2:
if len(uvs) >= 2:
face_uvs[face] = uvs
faces_islands = {}
faces_unparsed = faces_selected.copy()
for face in face_uvs:
if face in faces_unparsed:
face_uvs[face][0].select = True
bpy.ops.uv.select_linked() # Extend selection
# Collect faces
faces_island = [face]
for f in faces_unparsed:
if f != face and f.select and f.loops[0][uv_layers].select:
print("append "+str(f.index))
for f in faces_island:
# Assign Faces to island
faces_islands[face] = faces_island
print("Sets: {}x".format(len(faces_islands)))
# Align each island to its edges
for face in faces_islands:
align_island(face_uvs[face][0].uv, face_uvs[face]
[1].uv, faces_islands[face])
def align_island(uv_vert0, uv_vert1, faces):
bm = bmesh.from_edit_mesh(bpy.context.active_object.data)
uv_layers = bm.loops.layers.uv.verify()
print("Align {}x faces".format(len(faces)))
# Select faces
for face in faces:
for loop in face.loops:
loop[uv_layers].select = True
diff = uv_vert1 - uv_vert0
current_angle = math.atan2(diff.x, diff.y)
angle_to_rotate = round(current_angle / (math.pi/2)) * (math.pi/2) - current_angle
# For some reason bpy.ops.transform.rotate rotates in the opposite
# direction in Blender 2.83 than in other versions.
if float(bpy.app.version_string[0:4]) == 2.83:
angle_to_rotate = -angle_to_rotate
bpy.context.tool_settings.transform_pivot_point = 'CURSOR'
bpy.ops.uv.cursor_set(location=uv_vert0 + diff/2)
bpy.ops.transform.rotate(value=angle_to_rotate, orient_axis='Z', constraint_axis=(False, False, False), orient_type='GLOBAL', mirror=False, use_proportional_edit=False)