2025-07-01
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
import bpy
|
||||
import bmesh
|
||||
import numpy as np
|
||||
|
||||
from mathutils import Vector
|
||||
|
||||
from . import op_select_islands_outline
|
||||
from . import utilities_uv
|
||||
|
||||
|
||||
|
||||
class op(bpy.types.Operator):
|
||||
bl_idname = "uv.textools_stitch"
|
||||
bl_label = "Stitch"
|
||||
bl_description = "Stitch other Islands to the selection"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if bpy.context.area.ui_type != 'UV':
|
||||
return False
|
||||
if not bpy.context.active_object:
|
||||
return False
|
||||
if bpy.context.active_object.mode != 'EDIT':
|
||||
return False
|
||||
if bpy.context.active_object.type != 'MESH':
|
||||
return False
|
||||
if context.scene.tool_settings.use_uv_select_sync:
|
||||
return False
|
||||
if not bpy.context.object.data.uv_layers:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def execute(self, context):
|
||||
utilities_uv.multi_object_loop(main, self, context)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
|
||||
def main(self, context):
|
||||
bm = bmesh.from_edit_mesh(bpy.context.active_object.data)
|
||||
uv_layers = bm.loops.layers.uv.verify()
|
||||
|
||||
op_select_islands_outline.select_outline(self, context)
|
||||
selection = {loop for face in bm.faces if face.select for loop in face.loops if loop[uv_layers].select_edge}
|
||||
|
||||
if selection:
|
||||
selectionFaces = {loop.face for loop in selection}
|
||||
selectionFacesTargets = {loop.link_loop_radial_next.face for loop in selection}
|
||||
extended_selection = {loop.link_loop_radial_next for loop in selection}
|
||||
extended_selection.update(selection)
|
||||
|
||||
#Store selection
|
||||
utilities_uv.selection_store(bm, uv_layers)
|
||||
|
||||
islands, target_islands = utilities_uv.getSelectedUnselectedIslands(bm, uv_layers, selected_faces=selectionFaces, target_faces=selectionFacesTargets)
|
||||
remaining_islands = islands.copy()
|
||||
remaining_islands.extend(target_islands)
|
||||
|
||||
if islands:
|
||||
for island in islands:
|
||||
del remaining_islands[0]
|
||||
if remaining_islands:
|
||||
bpy.ops.uv.select_all(action='DESELECT')
|
||||
loop1 = next(iter(island)).loops[0]
|
||||
loop1[uv_layers].select=True
|
||||
bpy.ops.uv.select_linked()
|
||||
|
||||
# Selection original coordinates
|
||||
loop2 = loop1.link_loop_next
|
||||
coords_before = (Vector((loop1[uv_layers].uv.x, loop1[uv_layers].uv.y)), Vector((loop2[uv_layers].uv.x, loop2[uv_layers].uv.y)))
|
||||
|
||||
# Stitch
|
||||
op_select_islands_outline.select_outline(self, context)
|
||||
selectionBorder = {loop for face in island for loop in face.loops if loop[uv_layers].select_edge}
|
||||
selectionBorder.intersection_update(extended_selection)
|
||||
|
||||
loopsByTarget = [[] for _ in range(len(remaining_islands))]
|
||||
for loop in selectionBorder:
|
||||
targetFace = loop.link_loop_radial_next.face
|
||||
if targetFace not in island:
|
||||
for l, i in zip(loopsByTarget, remaining_islands):
|
||||
if targetFace in i:
|
||||
l.append(loop)
|
||||
#l.append(loop.link_loop_next)
|
||||
break
|
||||
|
||||
for grouped_loops in loopsByTarget:
|
||||
bpy.ops.uv.select_all(action='DESELECT')
|
||||
for base_loop in grouped_loops:
|
||||
base_loop[uv_layers].select = True
|
||||
base_loop[uv_layers].select_edge = True
|
||||
|
||||
bpy.ops.uv.stitch(use_limit=False, snap_islands=True, midpoint_snap=False, clear_seams=True, mode='EDGE')
|
||||
|
||||
# Relocate selection
|
||||
coords_after = (Vector((loop1[uv_layers].uv.x, loop1[uv_layers].uv.y)), Vector((loop2[uv_layers].uv.x, loop2[uv_layers].uv.y)))
|
||||
if coords_before != coords_after:
|
||||
loop1[uv_layers].select = True
|
||||
bpy.ops.uv.select_linked()
|
||||
new_island = utilities_uv.get_selected_uv_faces(bm, uv_layers)
|
||||
|
||||
displace = coords_before[0] - coords_after[0]
|
||||
vec_origin = coords_after[0]
|
||||
V1 = coords_before[1] - coords_before[0]
|
||||
V2 = coords_after[1] - coords_after[0]
|
||||
theta = - np.math.atan2(np.linalg.det([V1,V2]),np.dot(V1,V2))
|
||||
matrix = np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]])
|
||||
|
||||
for f in new_island:
|
||||
for loop in f.loops:
|
||||
uvs0 = loop[uv_layers].uv - vec_origin
|
||||
loop[uv_layers].uv = (vec_origin.x + matrix[0][0]*uvs0.x + matrix[0][1]*uvs0.y + displace.x, vec_origin.y + matrix[1][0]*uvs0.x + matrix[1][1]*uvs0.y + displace.y)
|
||||
|
||||
#Restore selection
|
||||
utilities_uv.selection_restore()
|
||||
|
||||
|
||||
bpy.utils.register_class(op)
|
||||
Reference in New Issue
Block a user