forked from franMarz/TexTools-Blender
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathop_island_align_sort.py
137 lines (109 loc) · 4.4 KB
/
op_island_align_sort.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import bpy
import bmesh
import operator
from itertools import chain
from mathutils import Vector
from . import utilities_uv
import imp
imp.reload(utilities_uv)
class op(bpy.types.Operator):
bl_idname = "uv.textools_island_align_sort"
bl_label = "Align & Sort"
bl_description = "Rotates UV islands to minimal bounds and sorts them horizontal or vertical"
bl_options = {'REGISTER', 'UNDO'}
is_vertical : bpy.props.BoolProperty(description="Vertical or Horizontal orientation", default=True)
padding : bpy.props.FloatProperty(description="Padding between UV islands", default=0.05)
@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.type != 'MESH':
return False
if bpy.context.active_object.mode != 'EDIT':
return False
if not bpy.context.object.data.uv_layers:
return False
if bpy.context.scene.tool_settings.use_uv_select_sync:
return False
return True
def execute(self, context):
all_ob_bounds = utilities_uv.multi_object_loop(main, context, self.is_vertical, self.padding, need_results=True)
if not any(all_ob_bounds):
return {'CANCELLED'}
utilities_uv.multi_object_loop(relocate, context, self.is_vertical, self.padding, all_ob_bounds, ob_num=0)
return {'FINISHED'}
def main(context, isVertical, padding):
bm = bmesh.from_edit_mesh(bpy.context.active_object.data)
uv_layers = bm.loops.layers.uv.verify()
selected_faces = [face for face in bm.faces if any([loop[uv_layers].select for loop in face.loops]) and face.select]
if not selected_faces:
return {}
boundsAll = utilities_uv.get_BBOX(selected_faces, bm, uv_layers)
islands = utilities_uv.getSelectionIslands(bm, uv_layers, selected_faces)
allSizes = {}
allBounds = {}
#Rotate to minimal bounds
for i, island in enumerate(islands):
utilities_uv.alignMinimalBounds(bm, uv_layers, island)
#Collect BBox sizes
bounds = utilities_uv.get_BBOX(island, bm, uv_layers)
allSizes[i] = max(bounds['width'], bounds['height']) + i*0.000001 #Make each size unique
allBounds[i] = bounds
#Position by sorted size in row
sortedSizes = sorted(allSizes.items(), key=operator.itemgetter(1)) #Sort by values, store tuples
sortedSizes.reverse()
offset = 0.0
for sortedSize in sortedSizes:
index = sortedSize[0]
island = islands[index]
bounds = allBounds[index]
#Offset Island
delta = Vector((boundsAll['min'].x - bounds['min'].x, boundsAll['max'].y - bounds['max'].y))
if(isVertical):
for face in island:
for loop in face.loops:
loop[uv_layers].uv += Vector((delta.x, delta.y-offset))
offset += bounds['height'] + padding
else:
for face in island:
for loop in face.loops:
loop[uv_layers].uv += Vector((delta.x+offset, delta.y))
offset += bounds['width'] + padding
return utilities_uv.get_BBOX(chain.from_iterable(islands), bm, uv_layers)
def relocate(context, isVertical, padding, all_ob_bounds, ob_num=0):
selection_mode = bpy.context.scene.tool_settings.uv_select_mode
bm = bmesh.from_edit_mesh(bpy.context.active_object.data)
uv_layers = bm.loops.layers.uv.verify()
islands = utilities_uv.getSelectionIslands(bm, uv_layers)
if ob_num > 0 :
if all_ob_bounds[ob_num]:
offset = 0.0
origin = Vector((0,0))
for i in range(0, ob_num):
if all_ob_bounds[i]:
if isVertical:
offset += all_ob_bounds[i]['height'] + padding
else:
offset += all_ob_bounds[i]['width'] + padding
for i in range(0, ob_num+1):
if all_ob_bounds[i]:
origin.x = all_ob_bounds[i]['min'].x
origin.y = all_ob_bounds[i]['max'].y
break
delta = Vector((origin.x - all_ob_bounds[ob_num]['min'].x, origin.y - all_ob_bounds[ob_num]['max'].y))
if isVertical:
for island in islands:
for face in island:
for loop in face.loops:
loop[uv_layers].uv += Vector((delta.x, delta.y-offset))
else:
for island in islands:
for face in island:
for loop in face.loops:
loop[uv_layers].uv += Vector((delta.x+offset, delta.y))
# Workaround for selection not flushing properly from loops to EDGE Selection Mode, apparently since UV edge selection support was added to the UV space
bpy.ops.uv.select_mode(type='VERTEX')
bpy.context.scene.tool_settings.uv_select_mode = selection_mode
bpy.utils.register_class(op)