[Bf-extensions-cvs] [a0e7faa] master: added uv_align_distribute.py(first commit)
Luca Carella
noreply at git.blender.org
Mon Jul 28 19:04:22 CEST 2014
Commit: a0e7faaa800e3a18d0b3d72fb7139fd617e9484e
Author: Luca Carella
Date: Mon Jul 28 18:12:24 2014 +0200
Branches: master
https://developer.blender.org/rBACa0e7faaa800e3a18d0b3d72fb7139fd617e9484e
added uv_align_distribute.py(first commit)
===================================================================
A uv_align_distribute.py
===================================================================
diff --git a/uv_align_distribute.py b/uv_align_distribute.py
new file mode 100644
index 0000000..d117f9d
--- /dev/null
+++ b/uv_align_distribute.py
@@ -0,0 +1,1066 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; version 2
+# of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+bl_info = {
+ "name": "UV Align/Distribute",
+ "author": "Rebellion (Luca Carella)",
+ "version": (1, 1),
+ "blender": (2, 7, 1),
+ "location": "UV/Image editor > Tool Panel, UV/Image editor UVs > menu",
+ "description": "Set of tools to help UV alignment\distribution",
+ "warning": "",
+ "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/UV/UV_Align_Distribution",
+ "category": "UV"}
+
+import math
+from collections import defaultdict
+
+import bmesh
+import bpy
+import mathutils
+from bpy.props import EnumProperty, BoolProperty, FloatProperty
+
+
+# Globals:
+bpy.types.Scene.relativeItems = EnumProperty(
+ items=[
+ ('UV_SPACE', 'Uv Space', 'Align to UV space'),
+ ('ACTIVE', 'Active Face', 'Align to active face\island'),
+ ('CURSOR', 'Cursor', 'Align to cursor')],
+ name="Relative to")
+
+bpy.types.Scene.selectionAsGroup = BoolProperty(
+ name="Selection as group",
+ description="Treat selection as group",
+ default=False)
+
+bm = None
+uvlayer = None
+
+
+def InitBMesh():
+ global bm
+ global uvlayer
+ bm = bmesh.from_edit_mesh(bpy.context.edit_object.data)
+ uvlayer = bm.loops.layers.uv.active
+
+
+def update():
+ bmesh.update_edit_mesh(bpy.context.edit_object.data, False, False)
+ # bm.to_mesh(bpy.context.object.data)
+ # bm.free()
+
+
+def GBBox(islands):
+ minX, minY = +1000
+ maxX, maxY = -1000
+ for island in islands:
+ for face_id in island:
+ face = bm.faces[face_id]
+ for loop in face.loops:
+ u, v = loop[uvlayer].uv
+ minX = min(u, minX)
+ minY = min(v, minY)
+ maxX = max(u, maxX)
+ maxY = max(v, maxY)
+
+ return mathutils.Vector((minX, minY)), mathutils.Vector((maxX, maxY))
+
+
+def GBBoxCenter(islands):
+ minX, minY = +1000
+ maxX, maxY = -1000
+ for island in islands:
+ for face_id in island:
+ face = bm.faces[face_id]
+ for loop in face.loops:
+ u, v = loop[uvlayer].uv
+ minX = min(u, minX)
+ minY = min(v, minY)
+ maxX = max(u, maxX)
+ maxY = max(v, maxY)
+
+ return (mathutils.Vector((minX, minY)) +
+ mathutils.Vector((maxX, maxY))) / 2
+
+
+def BBox(island):
+ minX, minY = +1000
+ maxX, maxY = -1000
+ # for island in islands:
+ # print(island)
+ for face_id in island:
+ face = bm.faces[face_id]
+ for loop in face.loops:
+ u, v = loop[uvlayer].uv
+ minX = min(u, minX)
+ minY = min(v, minY)
+ maxX = max(u, maxX)
+ maxY = max(v, maxY)
+
+ return mathutils.Vector((minX, minY)), mathutils.Vector((maxX, maxY))
+
+
+def BBoxCenter(island):
+ minX, minY = +1000
+ maxX, maxY = -1000
+ # for island in islands:
+ for face_id in island:
+ face = bm.faces[face_id]
+ for loop in face.loops:
+ u, v = loop[uvlayer].uv
+ minX = min(u, minX)
+ minY = min(v, minY)
+ maxX = max(u, maxX)
+ maxY = max(v, maxY)
+
+ return (mathutils.Vector((minX, minY)) +
+ mathutils.Vector((maxX, maxY))) / 2
+
+
+def islandAngle(island):
+ uvList = []
+ for face_id in island:
+ face = bm.faces[face_id]
+ for loop in face.loops:
+ uv = loop[bm.loops.layers.uv.active].uv
+ uvList.append(uv)
+
+ angle = math.degrees(mathutils.geometry.box_fit_2d(uvList))
+ return angle
+
+
+def moveIslands(vector, island):
+ for face_id in island:
+ face = bm.faces[face_id]
+ for loop in face.loops:
+ loop[bm.loops.layers.uv.active].uv += vector
+
+
+def rotateIsland(island, angle):
+ rad = math.radians(angle)
+ center = BBoxCenter(island)
+
+ for face_id in island:
+ face = bm.faces[face_id]
+ for loop in face.loops:
+ uv_act = bm.loops.layers.uv.active
+ x, y = loop[uv_act].uv
+ xt = x - center.x
+ yt = y - center.y
+ xr = (xt * math.cos(rad)) - (yt * math.sin(rad))
+ yr = (xt * math.sin(rad)) + (yt * math.cos(rad))
+ # loop[bm.loops.layers.uv.active].uv = trans
+ loop[bm.loops.layers.uv.active].uv.x = xr + center.x
+ loop[bm.loops.layers.uv.active].uv.y = yr + center.y
+ # print('fired')
+
+
+def scaleIsland(island, scaleX, scaleY):
+ scale = mathutils.Vector((scaleX, scaleY))
+ center = BBoxCenter(island)
+
+ for face_id in island:
+ face = bm.faces[face_id]
+ for loop in face.loops:
+ x = loop[bm.loops.layers.uv.active].uv.x
+ y = loop[bm.loops.layers.uv.active].uv.y
+ xt = x - center.x
+ yt = y - center.y
+ xs = xt * scaleX
+ ys = yt * scaleY
+ loop[bm.loops.layers.uv.active].uv.x = xs + center.x
+ loop[bm.loops.layers.uv.active].uv.y = ys + center.y
+
+
+def vectorDistance(vector1, vector2):
+ return math.sqrt(
+ math.pow((vector2.x - vector1.x), 2) +
+ math.pow((vector2.y - vector1.y), 2))
+
+
+def matchIsland(active, thresold, island):
+ for active_face_id in active:
+ active_face = bm.faces[active_face_id]
+
+ for active_loop in active_face.loops:
+ activeUVvert = active_loop[bm.loops.layers.uv.active].uv
+
+ for face_id in island:
+ face = bm.faces[face_id]
+
+ for loop in face.loops:
+ selectedUVvert = loop[bm.loops.layers.uv.active].uv
+ dist = vectorDistance(selectedUVvert, activeUVvert)
+
+ if dist <= thresold:
+ loop[bm.loops.layers.uv.active].uv = activeUVvert
+
+
+def getTargetPoint(context, islands):
+ if context.scene.relativeItems == 'UV_SPACE':
+ return mathutils.Vector((0.0, 0.0)), mathutils.Vector((1.0, 1.0))
+ elif context.scene.relativeItems == 'ACTIVE':
+ activeIsland = islands.activeIsland()
+ if not activeIsland:
+ return None
+ else:
+ return BBox(activeIsland)
+ elif context.scene.relativeItems == 'CURSOR':
+ return context.space_data.cursor_location,\
+ context.space_data.cursor_location
+
+
+def IslandSpatialSortX(islands):
+ spatialSort = []
+ for island in islands:
+ spatialSort.append((BBoxCenter(island).x, island))
+ spatialSort.sort()
+ return spatialSort
+
+
+def IslandSpatialSortY(islands):
+ spatialSort = []
+ for island in islands:
+ spatialSort.append((BBoxCenter(island).y, island))
+ spatialSort.sort()
+ return spatialSort
+
+
+def averageIslandDist(islands):
+ distX = 0
+ distY = 0
+ counter = 0
+
+ for i in range(len(islands)):
+ elem1 = BBox(islands[i][1])[1]
+ try:
+ elem2 = BBox(islands[i + 1][1])[0]
+ counter += 1
+ except:
+ break
+
+ distX += elem2.x - elem1.x
+ distY += elem2.y - elem1.y
+
+ avgDistX = distX / counter
+ avgDistY = distY / counter
+ return mathutils.Vector((avgDistX, avgDistY))
+
+
+def islandSize(island):
+ bbox = BBox(island)
+ sizeX = bbox[1].x - bbox[0].x
+ sizeY = bbox[1].y - bbox[0].y
+
+ return sizeX, sizeY
+
+
+class MakeIslands():
+
+ def __init__(self):
+ InitBMesh()
+ global bm
+ global uvlayer
+
+ self.face_to_verts = defaultdict(set)
+ self.vert_to_faces = defaultdict(set)
+ self.selectedIsland = set()
+
+ for face in bm.faces:
+ for loop in face.loops:
+ id = loop[uvlayer].uv.to_tuple(5), loop.vert.index
+ self.face_to_verts[face.index].add(id)
+ self.vert_to_faces[id].add(face.index)
+ if face.select:
+ if loop[uvlayer].select:
+ self.selectedIsland.add(face.index)
+
+ def addToIsland(self, face_id):
+ if face_id in self.faces_left:
+ # add the face itself
+ self.current_island.append(face_id)
+ self.faces_left.remove(face_id)
+ # and add all faces that share uvs with this face
+ verts = self.face_to_verts[face_id]
+ for vert in verts:
+ # print('looking at vert {}'.format(vert))
+ connected_faces = self.vert_to_faces[vert]
+ if connected_faces:
+ for face in connected_faces:
+ self.addToIsland(face)
+
+ def getIslands(self):
+ self.islands = []
+ self.faces_left = set(self.face_to_verts.keys())
+ while len(self.faces_left) > 0:
+ face_id = list(self.faces_left)[0]
+ self.current_island = []
+ self.addToIsland(face_id)
+ self.islands.append(self.current_island)
+
+ return self.islands
+
+ def activeIsland(self):
+ for island in self.islands:
+ try:
+ if bm.faces.active.index in island:
+ return island
+ except:
+ return None
+
+ def selectedIslands(self):
+ _selectedIslands = []
+ for
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-extensions-cvs
mailing list