Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2018-06-26 23:56:39 +0300
committerCampbell Barton <ideasman42@gmail.com>2018-06-26 23:56:39 +0300
commita61480c27103fbf449fd14ea8061b65c29f19eae (patch)
tree8d626b465ebe17936b7551aa91cc5b9d3b192607 /release/scripts/startup/bl_operators/uvcalc_smart_project.py
parenta3cd57ea8c57c10d4c65ddd51faa6cce14c98e10 (diff)
parent532c8ac58384309e77791e32ab78f448ad2a76a6 (diff)
Merge branch 'master' into blender2.8
Diffstat (limited to 'release/scripts/startup/bl_operators/uvcalc_smart_project.py')
-rw-r--r--release/scripts/startup/bl_operators/uvcalc_smart_project.py459
1 files changed, 228 insertions, 231 deletions
diff --git a/release/scripts/startup/bl_operators/uvcalc_smart_project.py b/release/scripts/startup/bl_operators/uvcalc_smart_project.py
index 25783653414..aebc0ae0313 100644
--- a/release/scripts/startup/bl_operators/uvcalc_smart_project.py
+++ b/release/scripts/startup/bl_operators/uvcalc_smart_project.py
@@ -26,7 +26,7 @@ from mathutils import (
import bpy
from bpy.types import Operator
-DEG_TO_RAD = 0.017453292519943295 # pi/180.0
+DEG_TO_RAD = 0.017453292519943295 # pi/180.0
# see bugs:
# - T31598 (when too small).
# - T48086 (when too big).
@@ -38,6 +38,7 @@ global USER_FILL_HOLES_QUALITY
USER_FILL_HOLES = None
USER_FILL_HOLES_QUALITY = None
+
def pointInTri2D(v, v1, v2, v3):
key = v1.x, v1.y, v2.x, v2.y, v3.x, v3.y
@@ -93,20 +94,25 @@ def pointInTri2D(v, v1, v2, v3):
def boundsIsland(faces):
- minx = maxx = faces[0].uv[0][0] # Set initial bounds.
+ minx = maxx = faces[0].uv[0][0] # Set initial bounds.
miny = maxy = faces[0].uv[0][1]
# print len(faces), minx, maxx, miny , maxy
for f in faces:
for uv in f.uv:
- x= uv.x
- y= uv.y
- if x<minx: minx= x
- if y<miny: miny= y
- if x>maxx: maxx= x
- if y>maxy: maxy= y
+ x = uv.x
+ y = uv.y
+ if x < minx:
+ minx = x
+ if y < miny:
+ miny = y
+ if x > maxx:
+ maxx = x
+ if y > maxy:
+ maxy = y
return minx, miny, maxx, maxy
+
"""
def boundsEdgeLoop(edges):
minx = maxx = edges[0][0] # Set initial bounds.
@@ -128,45 +134,51 @@ def boundsEdgeLoop(edges):
# Only for UV's
# only returns outline edges for intersection tests. and unique points.
+
def island2Edge(island):
# Vert index edges
edges = {}
- unique_points= {}
+ unique_points = {}
for f in island:
- f_uvkey= map(tuple, f.uv)
-
+ f_uvkey = map(tuple, f.uv)
for vIdx, edkey in enumerate(f.edge_keys):
unique_points[f_uvkey[vIdx]] = f.uv[vIdx]
- if f.v[vIdx].index > f.v[vIdx-1].index:
- i1= vIdx-1; i2= vIdx
+ if f.v[vIdx].index > f.v[vIdx - 1].index:
+ i1 = vIdx - 1
+ i2 = vIdx
else:
- i1= vIdx; i2= vIdx-1
+ i1 = vIdx
+ i2 = vIdx - 1
- try: edges[ f_uvkey[i1], f_uvkey[i2] ] *= 0 # sets any edge with more than 1 user to 0 are not returned.
- except: edges[ f_uvkey[i1], f_uvkey[i2] ] = (f.uv[i1] - f.uv[i2]).length,
+ try:
+ edges[f_uvkey[i1], f_uvkey[i2]] *= 0 # sets any edge with more than 1 user to 0 are not returned.
+ except:
+ edges[f_uvkey[i1], f_uvkey[i2]] = (f.uv[i1] - f.uv[i2]).length,
# If 2 are the same then they will be together, but full [a,b] order is not correct.
# Sort by length
-
length_sorted_edges = [(Vector(key[0]), Vector(key[1]), value) for key, value in edges.items() if value != 0]
- try: length_sorted_edges.sort(key = lambda A: -A[2]) # largest first
- except: length_sorted_edges.sort(lambda A, B: cmp(B[2], A[2]))
+ try:
+ length_sorted_edges.sort(key=lambda A: -A[2]) # largest first
+ except:
+ length_sorted_edges.sort(lambda A, B: cmp(B[2], A[2]))
# Its okay to leave the length in there.
- #for e in length_sorted_edges:
+ # for e in length_sorted_edges:
# e.pop(2)
# return edges and unique points
return length_sorted_edges, [v.to_3d() for v in unique_points.values()]
+
# ========================= NOT WORKING????
# Find if a points inside an edge loop, unordered.
# pt is and x/y
@@ -190,6 +202,7 @@ def pointInEdges(pt, edges):
return intersectCount % 2
"""
+
def pointInIsland(pt, island):
vec1, vec2, vec3 = Vector(), Vector(), Vector()
for f in island:
@@ -212,7 +225,7 @@ def pointInIsland(pt, island):
# box is (left,bottom, right, top)
def islandIntersectUvIsland(source, target, SourceOffset):
# Is 1 point in the box, inside the vertLoops
- edgeLoopsSource = source[6] # Pretend this is offset
+ edgeLoopsSource = source[6] # Pretend this is offset
edgeLoopsTarget = target[6]
# Edge intersect test
@@ -220,24 +233,24 @@ def islandIntersectUvIsland(source, target, SourceOffset):
for seg in edgeLoopsTarget:
i = geometry.intersect_line_line_2d(seg[0],
seg[1],
- SourceOffset+ed[0],
- SourceOffset+ed[1],
+ SourceOffset + ed[0],
+ SourceOffset + ed[1],
)
if i:
- return 1 # LINE INTERSECTION
+ return 1 # LINE INTERSECTION
# 1 test for source being totally inside target
SourceOffset.resize_3d()
for pv in source[7]:
- if pointInIsland(pv+SourceOffset, target[0]):
- return 2 # SOURCE INSIDE TARGET
+ if pointInIsland(pv + SourceOffset, target[0]):
+ return 2 # SOURCE INSIDE TARGET
# 2 test for a part of the target being totally inside the source.
for pv in target[7]:
- if pointInIsland(pv-SourceOffset, source[0]):
- return 3 # PART OF TARGET INSIDE SOURCE.
+ if pointInIsland(pv - SourceOffset, source[0]):
+ return 3 # PART OF TARGET INSIDE SOURCE.
- return 0 # NO INTERSECTION
+ return 0 # NO INTERSECTION
def rotate_uvs(uv_points, angle):
@@ -249,7 +262,7 @@ def rotate_uvs(uv_points, angle):
def optiRotateUvIsland(faces):
- uv_points = [uv for f in faces for uv in f.uv]
+ uv_points = [uv for f in faces for uv in f.uv]
angle = geometry.box_fit_2d(uv_points)
if angle != 0.0:
@@ -270,81 +283,78 @@ def mergeUvIslands(islandList):
global USER_FILL_HOLES
global USER_FILL_HOLES_QUALITY
-
# Pack islands to bottom LHS
# Sync with island
- #islandTotFaceArea = [] # A list of floats, each island area
- #islandArea = [] # a list of tuples ( area, w,h)
-
+ # islandTotFaceArea = [] # A list of floats, each island area
+ # islandArea = [] # a list of tuples ( area, w,h)
decoratedIslandList = []
islandIdx = len(islandList)
while islandIdx:
- islandIdx-=1
+ islandIdx -= 1
minx, miny, maxx, maxy = boundsIsland(islandList[islandIdx])
- w, h = maxx-minx, maxy-miny
+ w, h = maxx - minx, maxy - miny
totFaceArea = 0
- offset= Vector((minx, miny))
+ offset = Vector((minx, miny))
for f in islandList[islandIdx]:
for uv in f.uv:
uv -= offset
totFaceArea += f.area
- islandBoundsArea = w*h
+ islandBoundsArea = w * h
efficiency = abs(islandBoundsArea - totFaceArea)
# UV Edge list used for intersections as well as unique points.
edges, uniqueEdgePoints = island2Edge(islandList[islandIdx])
- decoratedIslandList.append([islandList[islandIdx], totFaceArea, efficiency, islandBoundsArea, w,h, edges, uniqueEdgePoints])
-
+ decoratedIslandList.append([islandList[islandIdx], totFaceArea, efficiency, islandBoundsArea, w, h, edges, uniqueEdgePoints])
# Sort by island bounding box area, smallest face area first.
# no.. chance that to most simple edge loop first.
- decoratedIslandListAreaSort =decoratedIslandList[:]
+ decoratedIslandListAreaSort = decoratedIslandList[:]
- decoratedIslandListAreaSort.sort(key = lambda A: A[3])
+ decoratedIslandListAreaSort.sort(key=lambda A: A[3])
# sort by efficiency, Least Efficient first.
decoratedIslandListEfficSort = decoratedIslandList[:]
# decoratedIslandListEfficSort.sort(lambda A, B: cmp(B[2], A[2]))
- decoratedIslandListEfficSort.sort(key = lambda A: -A[2])
+ decoratedIslandListEfficSort.sort(key=lambda A: -A[2])
# ================================================== THESE CAN BE TWEAKED.
# This is a quality value for the number of tests.
# from 1 to 4, generic quality value is from 1 to 100
- USER_STEP_QUALITY = ((USER_FILL_HOLES_QUALITY - 1) / 25.0) + 1
+ USER_STEP_QUALITY = ((USER_FILL_HOLES_QUALITY - 1) / 25.0) + 1
# If 100 will test as long as there is enough free space.
# this is rarely enough, and testing takes a while, so lower quality speeds this up.
# 1 means they have the same quality
- USER_FREE_SPACE_TO_TEST_QUALITY = 1 + (((100 - USER_FILL_HOLES_QUALITY)/100.0) *5)
+ USER_FREE_SPACE_TO_TEST_QUALITY = 1 + (((100 - USER_FILL_HOLES_QUALITY) / 100.0) * 5)
- #print 'USER_STEP_QUALITY', USER_STEP_QUALITY
- #print 'USER_FREE_SPACE_TO_TEST_QUALITY', USER_FREE_SPACE_TO_TEST_QUALITY
+ # print 'USER_STEP_QUALITY', USER_STEP_QUALITY
+ # print 'USER_FREE_SPACE_TO_TEST_QUALITY', USER_FREE_SPACE_TO_TEST_QUALITY
removedCount = 0
areaIslandIdx = 0
ctrl = Window.Qual.CTRL
- BREAK= False
+ BREAK = False
while areaIslandIdx < len(decoratedIslandListAreaSort) and not BREAK:
sourceIsland = decoratedIslandListAreaSort[areaIslandIdx]
# Already packed?
if not sourceIsland[0]:
- areaIslandIdx+=1
+ areaIslandIdx += 1
else:
efficIslandIdx = 0
while efficIslandIdx < len(decoratedIslandListEfficSort) and not BREAK:
if Window.GetKeyQualifiers() & ctrl:
- BREAK= True
+ BREAK = True
break
# Now we have 2 islands, if the efficiency of the islands lowers theres an
@@ -355,64 +365,60 @@ def mergeUvIslands(islandList):
targetIsland = decoratedIslandListEfficSort[efficIslandIdx]
-
if sourceIsland[0] == targetIsland[0] or\
- not targetIsland[0] or\
- not sourceIsland[0]:
+ not targetIsland[0] or\
+ not sourceIsland[0]:
pass
else:
#~ ([island, totFaceArea, efficiency, islandArea, w,h])
# Wasted space on target is greater then UV bounding island area.
-
#~ if targetIsland[3] > (sourceIsland[2]) and\ #
- #~ print USER_FREE_SPACE_TO_TEST_QUALITY
+ # ~ print USER_FREE_SPACE_TO_TEST_QUALITY
if targetIsland[2] > (sourceIsland[1] * USER_FREE_SPACE_TO_TEST_QUALITY) and\
- targetIsland[4] > sourceIsland[4] and\
- targetIsland[5] > sourceIsland[5]:
+ targetIsland[4] > sourceIsland[4] and\
+ targetIsland[5] > sourceIsland[5]:
# DEBUG # print '%.10f %.10f' % (targetIsland[3], sourceIsland[1])
# These enough spare space lets move the box until it fits
# How many times does the source fit into the target x/y
- blockTestXUnit = targetIsland[4]/sourceIsland[4]
- blockTestYUnit = targetIsland[5]/sourceIsland[5]
+ blockTestXUnit = targetIsland[4] / sourceIsland[4]
+ blockTestYUnit = targetIsland[5] / sourceIsland[5]
boxLeft = 0
-
# Distance we can move between whilst staying inside the targets bounds.
testWidth = targetIsland[4] - sourceIsland[4]
testHeight = targetIsland[5] - sourceIsland[5]
# Increment we move each test. x/y
- xIncrement = (testWidth / (blockTestXUnit * ((USER_STEP_QUALITY/50)+0.1)))
- yIncrement = (testHeight / (blockTestYUnit * ((USER_STEP_QUALITY/50)+0.1)))
+ xIncrement = (testWidth / (blockTestXUnit * ((USER_STEP_QUALITY / 50) + 0.1)))
+ yIncrement = (testHeight / (blockTestYUnit * ((USER_STEP_QUALITY / 50) + 0.1)))
# Make sure were not moving less then a 3rg of our width/height
- if xIncrement<sourceIsland[4]/3:
- xIncrement= sourceIsland[4]
- if yIncrement<sourceIsland[5]/3:
- yIncrement= sourceIsland[5]
-
+ if xIncrement < sourceIsland[4] / 3:
+ xIncrement = sourceIsland[4]
+ if yIncrement < sourceIsland[5] / 3:
+ yIncrement = sourceIsland[5]
- boxLeft = 0 # Start 1 back so we can jump into the loop.
- boxBottom= 0 #-yIncrement
+ boxLeft = 0 # Start 1 back so we can jump into the loop.
+ boxBottom = 0 # -yIncrement
- #~ testcount= 0
+ # ~ testcount= 0
while boxBottom <= testHeight:
# Should we use this? - not needed for now.
- #~ if Window.GetKeyQualifiers() & ctrl:
- #~ BREAK= True
- #~ break
+ # ~ if Window.GetKeyQualifiers() & ctrl:
+ # ~ BREAK= True
+ # ~ break
- ##testcount+=1
- #print 'Testing intersect'
+ # testcount+=1
+ # print 'Testing intersect'
Intersect = islandIntersectUvIsland(sourceIsland, targetIsland, Vector((boxLeft, boxBottom)))
- #print 'Done', Intersect
+ # print 'Done', Intersect
if Intersect == 1: # Line intersect, don't bother with this any more
pass
@@ -429,93 +435,92 @@ def mergeUvIslands(islandList):
# Move the test along its width + SMALL_NUM
#boxLeft += sourceIsland[4] + SMALL_NUM
boxLeft += sourceIsland[4]
- elif Intersect == 0: # No intersection?? Place it.
+ elif Intersect == 0: # No intersection?? Place it.
# Progress
- removedCount +=1
-#XXX Window.DrawProgressBar(0.0, 'Merged: %i islands, Ctrl to finish early.' % removedCount)
+ removedCount += 1
+# XXX Window.DrawProgressBar(0.0, 'Merged: %i islands, Ctrl to finish early.' % removedCount)
# Move faces into new island and offset
targetIsland[0].extend(sourceIsland[0])
- offset= Vector((boxLeft, boxBottom))
+ offset = Vector((boxLeft, boxBottom))
for f in sourceIsland[0]:
for uv in f.uv:
- uv+= offset
+ uv += offset
del sourceIsland[0][:] # Empty
-
# Move edge loop into new and offset.
# targetIsland[6].extend(sourceIsland[6])
- #while sourceIsland[6]:
- targetIsland[6].extend( [ (\
- (e[0]+offset, e[1]+offset, e[2])\
- ) for e in sourceIsland[6] ] )
+ # while sourceIsland[6]:
+ targetIsland[6].extend([(
+ (e[0] + offset, e[1] + offset, e[2])
+ ) for e in sourceIsland[6]])
del sourceIsland[6][:] # Empty
# Sort by edge length, reverse so biggest are first.
- try: targetIsland[6].sort(key = lambda A: A[2])
- except: targetIsland[6].sort(lambda B,A: cmp(A[2], B[2] ))
-
+ try:
+ targetIsland[6].sort(key=lambda A: A[2])
+ except:
+ targetIsland[6].sort(lambda B, A: cmp(A[2], B[2]))
targetIsland[7].extend(sourceIsland[7])
- offset= Vector((boxLeft, boxBottom, 0.0))
+ offset = Vector((boxLeft, boxBottom, 0.0))
for p in sourceIsland[7]:
- p+= offset
+ p += offset
del sourceIsland[7][:]
-
# Decrement the efficiency
- targetIsland[1]+=sourceIsland[1] # Increment totFaceArea
- targetIsland[2]-=sourceIsland[1] # Decrement efficiency
+ targetIsland[1] += sourceIsland[1] # Increment totFaceArea
+ targetIsland[2] -= sourceIsland[1] # Decrement efficiency
# IF we ever used these again, should set to 0, eg
- sourceIsland[2] = 0 # No area if anyone wants to know
+ sourceIsland[2] = 0 # No area if anyone wants to know
break
-
# INCREMENT NEXT LOCATION
if boxLeft > testWidth:
boxBottom += yIncrement
boxLeft = 0.0
else:
boxLeft += xIncrement
- ##print testcount
+ # print testcount
- efficIslandIdx+=1
- areaIslandIdx+=1
+ efficIslandIdx += 1
+ areaIslandIdx += 1
# Remove empty islands
i = len(islandList)
while i:
- i-=1
+ i -= 1
if not islandList[i]:
- del islandList[i] # Can increment islands removed here.
+ del islandList[i] # Can increment islands removed here.
# Takes groups of faces. assumes face groups are UV groups.
+
+
def getUvIslands(faceGroups, me):
# Get seams so we don't cross over seams
- edge_seams = {} # should be a set
+ edge_seams = {} # should be a set
for ed in me.edges:
if ed.use_seam:
- edge_seams[ed.key] = None # dummy var- use sets!
+ edge_seams[ed.key] = None # dummy var- use sets!
# Done finding seams
-
islandList = []
-#XXX Window.DrawProgressBar(0.0, 'Splitting %d projection groups into UV islands:' % len(faceGroups))
- #print '\tSplitting %d projection groups into UV islands:' % len(faceGroups),
+# XXX Window.DrawProgressBar(0.0, 'Splitting %d projection groups into UV islands:' % len(faceGroups))
+ # print '\tSplitting %d projection groups into UV islands:' % len(faceGroups),
# Find grouped faces
faceGroupIdx = len(faceGroups)
while faceGroupIdx:
- faceGroupIdx-=1
+ faceGroupIdx -= 1
faces = faceGroups[faceGroupIdx]
if not faces:
@@ -526,37 +531,38 @@ def getUvIslands(faceGroups, me):
for i, f in enumerate(faces):
for ed_key in f.edge_keys:
- if ed_key in edge_seams: # DELIMIT SEAMS! ;)
- edge_users[ed_key] = [] # so as not to raise an error
+ if ed_key in edge_seams: # DELIMIT SEAMS! ;)
+ edge_users[ed_key] = [] # so as not to raise an error
else:
- try: edge_users[ed_key].append(i)
- except: edge_users[ed_key] = [i]
+ try:
+ edge_users[ed_key].append(i)
+ except:
+ edge_users[ed_key] = [i]
# Modes
# 0 - face not yet touched.
# 1 - added to island list, and need to search
# 2 - touched and searched - don't touch again.
- face_modes = [0] * len(faces) # initialize zero - untested.
+ face_modes = [0] * len(faces) # initialize zero - untested.
- face_modes[0] = 1 # start the search with face 1
+ face_modes[0] = 1 # start the search with face 1
newIsland = []
newIsland.append(faces[0])
-
ok = True
while ok:
ok = True
while ok:
- ok= False
+ ok = False
for i in range(len(faces)):
- if face_modes[i] == 1: # search
+ if face_modes[i] == 1: # search
for ed_key in faces[i].edge_keys:
for ii in edge_users[ed_key]:
if i != ii and face_modes[ii] == 0:
- face_modes[ii] = ok = 1 # mark as searched
+ face_modes[ii] = ok = 1 # mark as searched
newIsland.append(faces[ii])
# mark as searched, don't look again.
@@ -574,7 +580,7 @@ def getUvIslands(faceGroups, me):
break
# if not ok will stop looping
-#XXX Window.DrawProgressBar(0.1, 'Optimizing Rotation for %i UV Islands' % len(islandList))
+# XXX Window.DrawProgressBar(0.1, 'Optimizing Rotation for %i UV Islands' % len(islandList))
for island in islandList:
optiRotateUvIsland(island)
@@ -584,9 +590,8 @@ def getUvIslands(faceGroups, me):
def packIslands(islandList):
if USER_FILL_HOLES:
-#XXX Window.DrawProgressBar(0.1, 'Merging Islands (Ctrl: skip merge)...')
- mergeUvIslands(islandList) # Modify in place
-
+ # XXX Window.DrawProgressBar(0.1, 'Merging Islands (Ctrl: skip merge)...')
+ mergeUvIslands(islandList) # Modify in place
# Now we have UV islands, we need to pack them.
@@ -603,16 +608,16 @@ def packIslands(islandList):
while islandIdx < len(islandList):
minx, miny, maxx, maxy = boundsIsland(islandList[islandIdx])
- w, h = maxx-minx, maxy-miny
+ w, h = maxx - minx, maxy - miny
if USER_ISLAND_MARGIN:
- minx -= USER_ISLAND_MARGIN# *w
- miny -= USER_ISLAND_MARGIN# *h
- maxx += USER_ISLAND_MARGIN# *w
- maxy += USER_ISLAND_MARGIN# *h
+ minx -= USER_ISLAND_MARGIN # *w
+ miny -= USER_ISLAND_MARGIN # *h
+ maxx += USER_ISLAND_MARGIN # *w
+ maxy += USER_ISLAND_MARGIN # *h
# recalc width and height
- w, h = maxx-minx, maxy-miny
+ w, h = maxx - minx, maxy - miny
if w < SMALL_NUM:
w = SMALL_NUM
@@ -628,24 +633,24 @@ def packIslands(islandList):
# Add to boxList. use the island idx for the BOX id.
packBoxes.append([0, 0, w, h])
- islandIdx+=1
+ islandIdx += 1
# Now we have a list of boxes to pack that syncs
# with the islands.
- #print '\tPacking UV Islands...'
-#XXX Window.DrawProgressBar(0.7, "Packing %i UV Islands..." % len(packBoxes) )
+ # print '\tPacking UV Islands...'
+# XXX Window.DrawProgressBar(0.7, "Packing %i UV Islands..." % len(packBoxes) )
# time1 = time.time()
packWidth, packHeight = geometry.box_pack_2d(packBoxes)
# print 'Box Packing Time:', time.time() - time1
- #if len(pa ckedLs) != len(islandList):
+ # if len(pa ckedLs) != len(islandList):
# raise ValueError("Packed boxes differs from original length")
- #print '\tWriting Packed Data to faces'
-#XXX Window.DrawProgressBar(0.8, "Writing Packed Data to faces")
+ # print '\tWriting Packed Data to faces'
+# XXX Window.DrawProgressBar(0.8, "Writing Packed Data to faces")
# Sort by ID, so there in sync again
islandIdx = len(islandList)
@@ -661,16 +666,16 @@ def packIslands(islandList):
xfactor = yfactor = 1.0 / max(packWidth, packHeight)
while islandIdx:
- islandIdx -=1
+ islandIdx -= 1
# Write the packed values to the UV's
xoffset = packBoxes[islandIdx][0] - islandOffsetList[islandIdx][0]
yoffset = packBoxes[islandIdx][1] - islandOffsetList[islandIdx][1]
- for f in islandList[islandIdx]: # Offsetting the UV's so they fit in there packed box
+ for f in islandList[islandIdx]: # Offsetting the UV's so they fit in there packed box
for uv in f.uv:
- uv.x= (uv.x+xoffset) * xfactor
- uv.y= (uv.y+yoffset) * yfactor
+ uv.x = (uv.x + xoffset) * xfactor
+ uv.y = (uv.y + yoffset) * yfactor
def VectoQuat(vec):
@@ -679,7 +684,8 @@ def VectoQuat(vec):
class thickface:
- __slost__= "v", "uv", "no", "area", "edge_keys"
+ __slost__ = "v", "uv", "no", "area", "edge_keys"
+
def __init__(self, face, uv_layer, mesh_verts):
self.v = [mesh_verts[i] for i in face.vertices]
self.uv = [uv_layer[i].uv for i in face.loop_indices]
@@ -700,18 +706,20 @@ def main_consts():
ROTMAT_2D_POS_45D = Matrix.Rotation(radians(45.0), 2)
RotMatStepRotation = []
- rot_angle = 22.5 #45.0/2
+ rot_angle = 22.5 # 45.0/2
while rot_angle > 0.1:
RotMatStepRotation.append([
Matrix.Rotation(radians(+rot_angle), 2),
Matrix.Rotation(radians(-rot_angle), 2),
- ])
+ ])
- rot_angle = rot_angle/2.0
+ rot_angle = rot_angle / 2.0
global ob
ob = None
+
+
def main(context,
island_margin,
projection_limit,
@@ -741,18 +749,18 @@ def main(context,
# Create the variables.
USER_PROJECTION_LIMIT = projection_limit
USER_ONLY_SELECTED_FACES = True
- USER_SHARE_SPACE = 1 # Only for hole filling.
+ USER_SHARE_SPACE = 1 # Only for hole filling.
USER_STRETCH_ASPECT = stretch_to_bounds
- USER_ISLAND_MARGIN = island_margin # Only for hole filling.
+ USER_ISLAND_MARGIN = island_margin # Only for hole filling.
USER_FILL_HOLES = 0
- USER_FILL_HOLES_QUALITY = 50 # Only for hole filling.
- USER_VIEW_INIT = 0 # Only for hole filling.
+ USER_FILL_HOLES_QUALITY = 50 # Only for hole filling.
+ USER_VIEW_INIT = 0 # Only for hole filling.
is_editmode = (context.active_object.mode == 'EDIT')
if is_editmode:
- obList = [ob for ob in [context.active_object] if ob and ob.type == 'MESH']
+ obList = [ob for ob in [context.active_object] if ob and ob.type == 'MESH']
else:
- obList = [ob for ob in context.selected_editable_objects if ob and ob.type == 'MESH']
+ obList = [ob for ob in context.selected_editable_objects if ob and ob.type == 'MESH']
USER_ONLY_SELECTED_FACES = False
if not obList:
@@ -770,15 +778,14 @@ def main(context,
time.sleep(10)
'''
-#~ XXX if not Draw.PupBlock(ob % len(obList), pup_block):
-#~ XXX return
-#~ XXX del ob
+# ~ XXX if not Draw.PupBlock(ob % len(obList), pup_block):
+# ~ XXX return
+# ~ XXX del ob
# Convert from being button types
USER_PROJECTION_LIMIT_CONVERTED = cos(USER_PROJECTION_LIMIT * DEG_TO_RAD)
- USER_PROJECTION_LIMIT_HALF_CONVERTED = cos((USER_PROJECTION_LIMIT/2) * DEG_TO_RAD)
-
+ USER_PROJECTION_LIMIT_HALF_CONVERTED = cos((USER_PROJECTION_LIMIT / 2) * DEG_TO_RAD)
# Toggle Edit mode
is_editmode = (context.active_object.mode == 'EDIT')
@@ -788,19 +795,18 @@ def main(context,
if USER_SHARE_SPACE:
# Sort by data name so we get consistent results
- obList.sort(key = lambda ob: ob.data.name)
- collected_islandList= []
+ obList.sort(key=lambda ob: ob.data.name)
+ collected_islandList = []
-#XXX Window.WaitCursor(1)
+# XXX Window.WaitCursor(1)
time1 = time.time()
# Tag as False so we don't operate on the same mesh twice.
-#XXX bpy.data.meshes.tag = False
+# XXX bpy.data.meshes.tag = False
for me in bpy.data.meshes:
me.tag = False
-
for ob in obList:
me = ob.data
@@ -810,7 +816,7 @@ def main(context,
# Tag as used
me.tag = True
- if not me.uv_layers: # Mesh has no UV Coords, don't bother.
+ if not me.uv_layers: # Mesh has no UV Coords, don't bother.
me.uv_layers.new()
uv_layer = me.uv_layers.active.data
@@ -821,7 +827,7 @@ def main(context,
else:
meshFaces = [thickface(f, uv_layer, me_verts) for i, f in enumerate(me.polygons)]
-#XXX Window.DrawProgressBar(0.1, 'SmartProj UV Unwrapper, mapping "%s", %i faces.' % (me.name, len(meshFaces)))
+# XXX Window.DrawProgressBar(0.1, 'SmartProj UV Unwrapper, mapping "%s", %i faces.' % (me.name, len(meshFaces)))
# =======
# Generate a projection list from face normals, this is meant to be smart :)
@@ -849,17 +855,15 @@ def main(context,
# 0d is 1.0
# 180 IS -0.59846
-
# Initialize projectVecs
if USER_VIEW_INIT:
# Generate Projection
- projectVecs = [Vector(Window.GetViewVector()) * ob.matrix_world.inverted().to_3x3()] # We add to this along the way
+ projectVecs = [Vector(Window.GetViewVector()) * ob.matrix_world.inverted().to_3x3()] # We add to this along the way
else:
projectVecs = []
newProjectVec = meshFaces[0].no
- newProjectMeshFaces = [] # Popping stuffs it up.
-
+ newProjectMeshFaces = [] # Popping stuffs it up.
# Pretend that the most unique angle is ages away to start the loop off
mostUniqueAngle = -1.0
@@ -867,14 +871,12 @@ def main(context,
# This is popped
tempMeshFaces = meshFaces[:]
-
-
# This while only gathers projection vecs, faces are assigned later on.
while 1:
# If theres none there then start with the largest face
# add all the faces that are close.
- for fIdx in range(len(tempMeshFaces)-1, -1, -1):
+ for fIdx in range(len(tempMeshFaces) - 1, -1, -1):
# Use half the angle limit so we don't overweight faces towards this
# normal and hog all the faces.
if newProjectVec.dot(tempMeshFaces[fIdx].no) > USER_PROJECTION_LIMIT_HALF_CONVERTED:
@@ -892,24 +894,23 @@ def main(context,
for fprop in newProjectMeshFaces:
averageVec += fprop.no * ((fprop.area * user_area_weight) + (1.0 - user_area_weight))
- if averageVec.x != 0 or averageVec.y != 0 or averageVec.z != 0: # Avoid NAN
+ if averageVec.x != 0 or averageVec.y != 0 or averageVec.z != 0: # Avoid NAN
projectVecs.append(averageVec.normalized())
-
# Get the next vec!
# Pick the face thats most different to all existing angles :)
- mostUniqueAngle = 1.0 # 1.0 is 0d. no difference.
- mostUniqueIndex = 0 # dummy
+ mostUniqueAngle = 1.0 # 1.0 is 0d. no difference.
+ mostUniqueIndex = 0 # dummy
- for fIdx in range(len(tempMeshFaces)-1, -1, -1):
- angleDifference = -1.0 # 180d difference.
+ for fIdx in range(len(tempMeshFaces) - 1, -1, -1):
+ angleDifference = -1.0 # 180d difference.
# Get the closest vec angle we are to.
for p in projectVecs:
- temp_angle_diff= p.dot(tempMeshFaces[fIdx].no)
+ temp_angle_diff = p.dot(tempMeshFaces[fIdx].no)
if angleDifference < temp_angle_diff:
- angleDifference= temp_angle_diff
+ angleDifference = temp_angle_diff
if angleDifference < mostUniqueAngle:
# We have a new most different angle
@@ -917,30 +918,28 @@ def main(context,
mostUniqueAngle = angleDifference
if mostUniqueAngle < USER_PROJECTION_LIMIT_CONVERTED:
- #print 'adding', mostUniqueAngle, USER_PROJECTION_LIMIT, len(newProjectMeshFaces)
+ # print 'adding', mostUniqueAngle, USER_PROJECTION_LIMIT, len(newProjectMeshFaces)
# Now weight the vector to all its faces, will give a more direct projection
# if the face its self was not representative of the normal from surrounding faces.
newProjectVec = tempMeshFaces[mostUniqueIndex].no
newProjectMeshFaces = [tempMeshFaces.pop(mostUniqueIndex)]
-
else:
- if len(projectVecs) >= 1: # Must have at least 2 projections
+ if len(projectVecs) >= 1: # Must have at least 2 projections
break
-
# If there are only zero area faces then its possible
# there are no projectionVecs
if not len(projectVecs):
Draw.PupMenu('error, no projection vecs where generated, 0 area faces can cause this.')
return
- faceProjectionGroupList =[[] for i in range(len(projectVecs)) ]
+ faceProjectionGroupList = [[] for i in range(len(projectVecs))]
# MAP and Arrange # We know there are 3 or 4 faces here
- for fIdx in range(len(meshFaces)-1, -1, -1):
+ for fIdx in range(len(meshFaces) - 1, -1, -1):
fvec = meshFaces[fIdx].no
i = len(projectVecs)
@@ -949,11 +948,11 @@ def main(context,
bestAngIdx = 0
# Cycle through the remaining, first already done
- while i-1:
- i-=1
+ while i - 1:
+ i -= 1
newAng = fvec.dot(projectVecs[i])
- if newAng > bestAng: # Reverse logic for dotvecs
+ if newAng > bestAng: # Reverse logic for dotvecs
bestAng = newAng
bestAngIdx = i
@@ -962,7 +961,6 @@ def main(context,
# Cull faceProjectionGroupList,
-
# Now faceProjectionGroupList is full of faces that face match the project Vecs list
for i in range(len(projectVecs)):
# Account for projectVecs having no faces.
@@ -979,7 +977,6 @@ def main(context,
# XXX - note, between mathutils in 2.4 and 2.5 the order changed.
f_uv[j][:] = (MatQuat * v.co).xy
-
if USER_SHARE_SPACE:
# Should we collect and pack later?
islandList = getUvIslands(faceProjectionGroupList, me)
@@ -990,12 +987,11 @@ def main(context,
islandList = getUvIslands(faceProjectionGroupList, me)
packIslands(islandList)
-
# update the mesh here if we need to.
# We want to pack all in 1 go, so pack now
if USER_SHARE_SPACE:
-#XXX Window.DrawProgressBar(0.9, "Box Packing for all objects...")
+ # XXX Window.DrawProgressBar(0.9, "Box Packing for all objects...")
packIslands(collected_islandList)
print("Smart Projection time: %.2f" % (time.time() - time1))
@@ -1006,31 +1002,32 @@ def main(context,
bpy.ops.object.mode_set(mode='EDIT')
if use_aspect:
- import bmesh
- aspect = context.scene.uvedit_aspect(context.active_object)
- if aspect[0] > aspect[1]:
- aspect[0] = aspect[1]/aspect[0];
- aspect[1] = 1.0
- else:
- aspect[1] = aspect[0]/aspect[1];
- aspect[0] = 1.0
+ import bmesh
+ aspect = context.scene.uvedit_aspect(context.active_object)
+ if aspect[0] > aspect[1]:
+ aspect[0] = aspect[1] / aspect[0]
+ aspect[1] = 1.0
+ else:
+ aspect[1] = aspect[0] / aspect[1]
+ aspect[0] = 1.0
- bm = bmesh.from_edit_mesh(me)
+ bm = bmesh.from_edit_mesh(me)
- uv_act = bm.loops.layers.uv.active
+ uv_act = bm.loops.layers.uv.active
- faces = [f for f in bm.faces if f.select]
+ faces = [f for f in bm.faces if f.select]
- for f in faces:
- for l in f.loops:
- l[uv_act].uv[0] *= aspect[0]
- l[uv_act].uv[1] *= aspect[1]
+ for f in faces:
+ for l in f.loops:
+ l[uv_act].uv[0] *= aspect[0]
+ l[uv_act].uv[1] *= aspect[1]
dict_matrix.clear()
-#XXX Window.DrawProgressBar(1.0, "")
-#XXX Window.WaitCursor(0)
-#XXX Window.RedrawAll()
+# XXX Window.DrawProgressBar(1.0, "")
+# XXX Window.WaitCursor(0)
+# XXX Window.RedrawAll()
+
"""
pup_block = [\
@@ -1052,41 +1049,41 @@ from bpy.props import FloatProperty, BoolProperty
class SmartProject(Operator):
"""This script projection unwraps the selected faces of a mesh """ \
- """(it operates on all selected mesh objects, and can be used """ \
- """to unwrap selected faces, or all faces)"""
+ """(it operates on all selected mesh objects, and can be used """ \
+ """to unwrap selected faces, or all faces)"""
bl_idname = "uv.smart_project"
bl_label = "Smart UV Project"
bl_options = {'REGISTER', 'UNDO'}
angle_limit = FloatProperty(
- name="Angle Limit",
- description="Lower for more projection groups, higher for less distortion",
- min=1.0, max=89.0,
- default=66.0,
- )
+ name="Angle Limit",
+ description="Lower for more projection groups, higher for less distortion",
+ min=1.0, max=89.0,
+ default=66.0,
+ )
island_margin = FloatProperty(
- name="Island Margin",
- description="Margin to reduce bleed from adjacent islands",
- unit='LENGTH', subtype='DISTANCE',
- min=0.0, max=1.0,
- default=0.0,
- )
+ name="Island Margin",
+ description="Margin to reduce bleed from adjacent islands",
+ unit='LENGTH', subtype='DISTANCE',
+ min=0.0, max=1.0,
+ default=0.0,
+ )
user_area_weight = FloatProperty(
- name="Area Weight",
- description="Weight projections vector by faces with larger areas",
- min=0.0, max=1.0,
- default=0.0,
- )
+ name="Area Weight",
+ description="Weight projections vector by faces with larger areas",
+ min=0.0, max=1.0,
+ default=0.0,
+ )
use_aspect = BoolProperty(
- name="Correct Aspect",
- description="Map UVs taking image aspect ratio into account",
- default=True
- )
+ name="Correct Aspect",
+ description="Map UVs taking image aspect ratio into account",
+ default=True
+ )
stretch_to_bounds = BoolProperty(
- name="Stretch to UV Bounds",
- description="Stretch the final output to texture bounds",
- default=True,
- )
+ name="Stretch to UV Bounds",
+ description="Stretch the final output to texture bounds",
+ default=True,
+ )
@classmethod
def poll(cls, context):