Updated for new Mathutils (should be faster)

uses Mesh rather then NMesh
uses expernal box packer
uv coords are not stretched anynore.
This commit is contained in:
Campbell Barton
2005-12-18 21:41:50 +00:00
parent c9de5c5b05
commit 4a027d8124

View File

@@ -1,27 +1,26 @@
#!BPY
""" Registration info for Blender menus: <- these words are ignored
Name: 'ArchiMap UV Unwrapper'
Blender: 237
Name: 'ArchiMap UV Projection Unwrapper'
Blender: 240
Group: 'UV'
Tooltip: 'ArchiMap UV Unwrap Mesh faces.'
Tooltip: 'ArchiMap UV Unwrap mesh faces for all select mesh objects'
"""
__author__ = "Campbell Barton"
__url__ = ("blender", "elysiun")
__version__ = "1.0 6/13/05"
__version__ = "1.1 12/18/05"
__bpydoc__ = """\
This script projection unwraps the selected faces of a mesh.
It operates on all selected mesh objects, and can be set to unwrap
it operates on all selected mesh objects, and can be set to unwrap
selected faces, or all faces.
"""
# --------------------------------------------------------------------------
# Archimap UV Projection Unwrapper v1.0 by Campbell Barton (AKA Ideasman)
# Archimap UV Projection Unwrapper v1.1 by Campbell Barton (AKA Ideasman)
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
@@ -43,509 +42,23 @@ selected faces, or all faces.
# --------------------------------------------------------------------------
from Blender import *
from Blender import Mathutils
from Blender.Mathutils import *
from Blender.Mathutils import CrossVecs, Matrix, Vector, RotationMatrix, DotVecs, TriangleArea
from math import cos, acos,pi,sqrt
from math import cos
try:
import sys as py_sys
except:
py_sys = None
DEG_TO_RAD = pi/180.0
DEG_TO_RAD = 0.017453292519943295 # pi/180.0
SMALL_NUM = 0.000000001
BIG_NUM = 1e15
try:
dummy = Mathutils.Matrix( Mathutils.Matrix() )
del dummy
NEW_2_38_MATHUTILS = True
except TypeError:
NEW_2_38_MATHUTILS = False
global USER_FILL_HOLES
global USER_FILL_HOLES_QUALITY
USER_FILL_HOLES = None
USER_FILL_HOLES_QUALITY = None
# ================================================== USER_BOX_PACK_MOD.py
from Blender import NMesh, Window, sys
# a box packing vert
class vt:
def __init__(self, x,y):
self.x, self.y = x, y
self.free = 15
# Set flags so cant test bottom left of 0/0
#~ BLF = 1; TRF = 2; TLF = 4; BRF = 8
#self.users = [] # A list of boxes.
# Rather then users, store Quadrents
self.blb = self.tlb = self.brb = self.trb = None
# A hack to remember the box() that last intersectec this vert
self.intersectCache = ([], [], [], [])
class vertList:
def __init__(self, verts=[]):
self.verts = verts
# Sorts closest first. - uses the box w/h as a bias,
# this makes it so its less likely to have lots of poking out bits
# that use too much
# Lambada based sort
def sortCorner(self,w,h):
self.verts.sort(lambda A, B: cmp(max(A.x+w, A.y+h) , max(B.x+w, B.y+h))) # Reverse area sort
class box:
global packedVerts
def __init__(self, width, height, id=None):
global packedVerts
self.id= id
self.area = width * height # real area
self.farea = width + height # fake area
#self.farea = float(min(width, height)) / float(max(width, height)) # fake area
self.width = width
self.height = height
# Append 4 new verts
# (BL,TR,TL,BR) / 0,1,2,3
self.v = [vt(0,0), vt(width,height), vt(0,height), vt(width,0)]
# Set the interior quadrents as used.
self.v[0].free &= ~TRF
self.v[1].free &= ~BLF
self.v[2].free &= ~BRF
self.v[3].free &= ~TLF
#for v in self.v:
# v.users.append(self)
self.v[0].trb = self
self.v[1].blb = self
self.v[2].brb = self
self.v[3].tlb = self
# Updates verts 3 & 4 from 1 and 2
# since 3 and 4 are only there foill need is resizing/ rotating of patterns on the fly while I painr new box placement
# but may be merged later with other verts
def updateV34(self):
self.v[TL].x = self.v[BL].x
self.v[TL].y = self.v[TR].y
self.v[BR].x = self.v[TR].x
self.v[BR].y = self.v[BL].y
def setLeft(self, lft=None):
self.v[TR].x = lft + self.v[TR].x - self.v[BL].x
self.v[BL].x = lft
# update othere verts
self.updateV34()
def setRight(self, rgt=None):
self.v[BL].x = rgt - (self.v[TR].x - self.v[BL].x)
self.v[TR].x = rgt
self.updateV34()
def setBottom(self, btm=None):
self.v[TR].y = btm + self.v[TR].y - self.v[BL].y
self.v[BL].y = btm
self.updateV34()
def setTop(self, tp=None):
self.v[BL].y = tp - (self.v[TR].y - self.v[BL].y)
self.v[TR].y = tp
self.updateV34()
def getLeft(self):
return self.v[BL].x
def getRight(self):
return self.v[TR].x
def getBottom(self):
return self.v[BL].y
def getTop(self):
return self.v[TR].y
# Returns none, meaning it didnt overlap any new boxes
def overlapAll(self, boxLs, intersectCache): # Flag index lets us know which quadere
if self.v[BL].x < 0:
return None
elif self.v[BL].y < 0:
return None
else:
bIdx = len(intersectCache)
while bIdx:
bIdx-=1
b = intersectCache[bIdx]
if not (self.v[TR].y <= b.v[BL].y or\
self.v[BL].y >= b.v[TR].y or\
self.v[BL].x >= b.v[TR].x or\
self.v[TR].x <= b.v[BL].x ):
return None # Intersection with existing box
#return 0 # Must keep looking
for b in boxLs.boxes:
if not (self.v[TR].y <= b.v[BL].y or\
self.v[BL].y >= b.v[TR].y or\
self.v[BL].x >= b.v[TR].x or\
self.v[TR].x <= b.v[BL].x ):
return b # Intersection with new box.
return 0
def place(self, vert, quad):
if quad == BLF:
self.setLeft(vert.x)
self.setBottom(vert.y)
elif quad == TRF:
self.setRight(vert.x)
self.setBottom(vert.y)
elif quad == TLF:
self.setLeft(vert.x)
self.setTop(vert.y)
elif quad == BRF:
self.setRight(vert.x)
self.setTop(vert.y)
# Trys to lock a box onto another box's verts
# cleans up double verts after
def tryVert(self, boxes, baseVert):
flagIndex = -1
for freeQuad in quadFlagLs:
flagIndex +=1
#print 'Testing ', self.width
if not baseVert.free & freeQuad:
continue
self.place(baseVert, freeQuad)
overlapBox = self.overlapAll(boxes, baseVert.intersectCache[flagIndex])
if overlapBox == 0: # There is no overlap
baseVert.free &= ~freeQuad # Removes quad
# Appends all verts but the one that matches. this removes the need for remove doubles
for vIdx in range(4): # (BL,TR,TL,BR): # (BL,TR,TL,BR) / 0,1,2,3
self_v = self.v[vIdx] # shortcut
if not (self_v.x == baseVert.x and self_v.y == baseVert.y):
packedVerts.verts.append(self_v)
else:
baseVert.free &= self.v[vIdx].free # make sure the
# Inherit used boxes from old verts
if self_v.blb: baseVert.blb = self_v.blb
if self_v.brb: baseVert.brb = self_v.brb #print 'inherit2'
if self_v.tlb: baseVert.tlb = self_v.tlb #print 'inherit3'
if self_v.trb: baseVert.trb = self_v.trb #print 'inherit4'
self.v[vIdx] = baseVert
# ========================== WHY DOSENT THIS WORK???
#~ if baseVert.tlb and baseVert.trb:
#~ if self == baseVert.tlb or self == baseVert.trb:
#~ if baseVert.tlb.height > baseVert.trb.height:
#~ #baseVert.trb.v[TL].free &= ~TLF & ~BLF
#~ baseVert.trb.v[TL].free &= ~TLF
#~ baseVert.trb.v[TL].free &= ~BLF
#~ elif baseVert.tlb.height < baseVert.trb.height:
#~ #baseVert.trb.v[TL].free &= ~TLF & ~BLF
#~ baseVert.tlb.v[TR].free &= ~TRF
#~ baseVert.tlb.v[TR].free &= ~BRF
#~ else: # same
#~ baseVert.tlb.v[TR].free &= ~BLF
#~ baseVert.trb.v[TL].free &= ~BRF
#~ if baseVert.blb and baseVert.brb:
#~ if self == baseVert.blb or self == baseVert.brb:
#~ if baseVert.blb.height > baseVert.brb.height:
#~ #baseVert.trb.v[TL].free &= ~TLF & ~BLF
#~ baseVert.brb.v[BL].free &= ~TLF
#~ baseVert.brb.v[BL].free &= ~BLF
#~ elif baseVert.blb.height < baseVert.brb.height:
#~ #baseVert.trb.v[TL].free &= ~TLF & ~BLF
#~ baseVert.blb.v[BR].free &= ~TRF
#~ baseVert.blb.v[BR].free &= ~BRF
#~ else: # same
#~ baseVert.blb.v[BR].free &= ~TLF
#~ baseVert.brb.v[BL].free &= ~TRF
#~ # print 'Hay', baseVert.tlb.height, baseVert.trb.height
return 1 # Working
# We have a box that intersects that quadrent.
elif overlapBox != None: # None is used for a box thats alredt in the freq list.
# There was an overlap, add this box to the verts list
#quadFlagLs = (BLF,BRF,TLF,TRF)
baseVert.intersectCache[flagIndex].append(overlapBox)
return 0
class boxList:
global packedVerts
def __init__(self, boxes):
self.boxes = boxes
# keep a running update of the width and height so we know the area
# initialize with first box, fixes but where we whwere only packing 1 box
self.width = 0
self.height = 0
if len(boxes) > 0:
for b in boxes:
self.width = max(self.width, b.width)
self.height = max(self.height, b.height)
# boxArea is the total area of all boxes in the list,
# can be used with packArea() to determine waistage.
self.boxArea = 0 # incremented with addBox()
# Just like MyBoxLs.boxes.append(), but sets bounds
def addBoxPack(self, box):
# Resize this boxlist bounds for the current box.
self.width = max(self.width, box.getRight())
self.height = max(self.height, box.getTop())
self.boxArea += box.area
# iterate through these
#~ quadFlagLs = (1,8,4,2)
#~ # Flags for vert idx used quads
#~ BLF = 1; TRF = 2; TLF = 4; BRF = 8
#~ quadFlagLs = (BLF,BRF,TLF,TRF)
# Look through all the free vert quads and see if there are some we can remove
'''
for v in box.v:
# Is my bottom being used.
if v.free & BLF and v.free & BRF: # BLF and BRF
for b in self.boxes:
if b.v[TR].y == v.y:
if b.v[TR].x > v.x:
if b.v[BL].x < v.x:
v.free &= ~BLF # Removes quad
v.free &= ~BRF # Removes quad
# Is my left being used.
if v.free & BLF and v.free & TLF:
for b in self.boxes:
if b.v[TR].x == v.x:
if b.v[TR].y > v.y:
if b.v[BL].y < v.y:
v.free &= ~BLF # Removes quad
v.free &= ~TLF # Removes quad
if v.free & TRF and v.free & TLF:
# Is my top being used.
for b in self.boxes:
if b.v[BL].y == v.y:
if b.v[TR].x > v.x:
if b.v[BL].x < v.x:
v.free &= ~TLF # Removes quad
v.free &= ~TRF # Removes quad
# Is my right being used.
if v.free & TRF and v.free & BRF:
for b in self.boxes:
if b.v[BL].x == v.x:
if b.v[TR].y > v.y:
if b.v[BL].y < v.y:
v.free &= ~BRF # Removes quad
v.free &= ~TRF # Removes quad
'''
self.boxes.append(box)
# Just like MyBoxLs.boxes.append(), but sets bounds
def addBox(self, box):
self.boxes.append(box)
self.boxArea += box.area
# The area of the backing bounds.
def packedArea(self):
return self.width * self.height
# Sort boxes by area
# TODO REPLACE WITH SORT(LAMBDA(CMP...))
def sortArea(self):
self.boxes.sort(lambda A, B: cmp(B.area, A.area) ) # Reverse area sort
# BLENDER only
def draw(self):
m = NMesh.GetRaw()
for b in self.boxes:
z = min(b.width, b.height ) / max(b.width, b.height )
#z = b.farea
#z=0
f = NMesh.Face()
m.verts.append(NMesh.Vert(b.getLeft(), b.getBottom(), z))
f.v.append(m.verts[-1])
m.verts.append(NMesh.Vert(b.getRight(), b.getBottom(), z))
f.v.append(m.verts[-1])
m.verts.append(NMesh.Vert(b.getRight(), b.getTop(), z))
f.v.append(m.verts[-1])
m.verts.append(NMesh.Vert(b.getLeft(), b.getTop(), z))
f.v.append(m.verts[-1])
m.faces.append(f)
NMesh.PutRaw(m, 's')
Window.Redraw(1)
def pack(self):
global packedVerts
packedVerts = vertList()
self.sortArea()
if len(self.boxes) == 0:
return
packedboxes = boxList([self.boxes[0]])
# Remove verts we KNOW cant be added to
unpackedboxes = boxList(self.boxes[1:])
# STart with this box
packedVerts.verts.extend(packedboxes.boxes[0].v)
while unpackedboxes.boxes != []:
freeBoxIdx = 0
while freeBoxIdx < len(unpackedboxes.boxes):
# Sort the verts with this boxes dimensions as a bias, so less poky out bits are made.
packedVerts.sortCorner(unpackedboxes.boxes[freeBoxIdx].width, unpackedboxes.boxes[freeBoxIdx].height)
vertIdx = 0
while vertIdx < len(packedVerts.verts):
baseVert = packedVerts.verts[vertIdx]
if baseVert.free != 0:
# This will lock the box if its possibel
if unpackedboxes.boxes[freeBoxIdx].tryVert(packedboxes, baseVert):
packedboxes.addBoxPack(unpackedboxes.boxes[freeBoxIdx])
unpackedboxes.boxes.pop(freeBoxIdx)
freeBoxIdx = -1
break
vertIdx +=1
freeBoxIdx +=1
self.width = packedboxes.width
self.height = packedboxes.height
# All boxes as a list - X/Y/WIDTH/HEIGHT
def list(self):
ls = []
for b in self.boxes:
ls.append( (b.id, b.getLeft(), b.getBottom(), b.width, b.height ) )
return ls
''' Define all globals here '''
# vert IDX's, make references easier to understand.
BL = 0; TR = 1; TL = 2; BR = 3
# iterate through these
quadFlagLs = (1,8,4,2)
# Flags for vert idx used quads
BLF = 1; TRF = 2; TLF = 4; BRF = 8
quadFlagLs = (BLF,BRF,TLF,TRF)
# Global vert pool, stores used lists
packedVerts = vertList()
# Packs a list w/h's into box types and places then #Iter times
def boxPackIter(boxLs, iter=1, draw=0):
iterIdx = 0
bestArea = None
# Iterate over packing the boxes to get the best FIT!
while iterIdx < iter:
myBoxLs = boxList([])
for b in boxLs:
myBoxLs.addBox( box(b[1], b[2], b[0]) ) # w/h/id
myBoxLs.pack()
# myBoxLs.draw() # Draw as we go?
newArea = myBoxLs.packedArea()
#print 'pack test %s of %s, area:%.2f' % (iterIdx, iter, newArea)
# First time?
if bestArea == None:
bestArea = newArea
bestBoxLs = myBoxLs
elif newArea < bestArea:
bestArea = newArea
bestBoxLs = myBoxLs
iterIdx+=1
if draw:
bestBoxLs.draw()
#print 'best area: %.4f, %.2f%% efficient' % (bestArea, (float(bestBoxLs.boxArea) / (bestArea+0.000001))*100)
return bestBoxLs.width, bestBoxLs.height, bestBoxLs.list()
# END USER_BOX_PACK_MOD.py
# ==============================================================
# Box Packer is included for distrobution.
#import box_pack_mod
#reload(box_pack_mod)
import boxpack2d
# reload(boxpack2d)
@@ -622,24 +135,6 @@ def lineIntersection2D(x1,y1, x2,y2, _x1,_y1, _x2,_y2):
else:
return None, None
def triArea(p1, p2, p3):
return CrossVecs(p1-p2, p3-p2).length/2
# IS a point inside our triangle?
'''
def pointInTri2D(PT, triP1, triP2, triP3):
def triArea(p1, p2, p3):
return CrossVecs(p1-p2, p3-p2).length /2
area1 = triArea(PT, triP2, triP3)
area2 = triArea(PT, triP1, triP3)
area3 = triArea(PT, triP1, triP2)
triArea = triArea(triP1, triP2, triP3)
if area1 + area2 + area3 > triArea+0.01:
return False
else:
return True
'''
dict_matrix = {}
def pointInTri2D(v, v1, v2, v3):
@@ -655,13 +150,13 @@ def pointInTri2D(v, v1, v2, v3):
side1 = v2 - v1
side2 = v3 - v1
nor = Mathutils.CrossVecs(side1, side2)
nor = CrossVecs(side1, side2)
l1 = [side1[0], side1[1], side1[2]]
l2 = [side2[0], side2[1], side2[2]]
l3 = [nor[0], nor[1], nor[2]]
mtx = Mathutils.Matrix(l1, l2, l3)
mtx = Matrix(l1, l2, l3)
# Zero area 2d tri, even tho we throw away zerop area faces
# the projection UV can result in a zero area UV.
@@ -673,24 +168,17 @@ def pointInTri2D(v, v1, v2, v3):
dict_matrix[key] = mtx
if NEW_2_38_MATHUTILS:
uvw = (v - v1) * mtx
else:
uvw = Mathutils.VecMultMat(v - v1, mtx)
uvw = (v - v1) * mtx
return 0 <= uvw[0] and 0 <= uvw[1] and uvw[0] + uvw[1] <= 1
def faceArea(f):
if len(f) == 3:
return triArea(f.v[0].co, f.v[1].co, f.v[2].co)
elif len(f) == 4:
if len(f.v) == 3:
return TriangleArea(f.v[0].co, f.v[1].co, f.v[2].co)
elif len(f.v) == 4:
return\
triArea(f.v[0].co, f.v[1].co, f.v[2].co) +\
triArea(f.v[0].co, f.v[2].co, f.v[3].co)
TriangleArea(f.v[0].co, f.v[1].co, f.v[2].co) +\
TriangleArea(f.v[0].co, f.v[2].co, f.v[3].co)
def boundsIsland(faces):
@@ -730,7 +218,7 @@ def island2Edge(island):
edges = {}
for f in island:
for vIdx in range(len(f)):
for vIdx in range(len(f.v)):
if f.v[vIdx].index > f.v[vIdx-1].index:
edges[((f.uv[vIdx-1][0], f.uv[vIdx-1][1]), (f.uv[vIdx][0], f.uv[vIdx][1]))] =\
(Vector([f.uv[vIdx-1][0], f.uv[vIdx-1][1]]) - Vector([f.uv[vIdx][0], f.uv[vIdx][1]])).length
@@ -794,7 +282,7 @@ def pointInIsland(pt, island):
if pointInTri2D(pt, vec1, vec2, vec3):
return True
if len(f) == 4:
if len(f.v) == 4:
vec1.x, vec1.y = f.uv[0]
vec2.x, vec2.y = f.uv[2]
vec3.x, vec3.y = f.uv[3]
@@ -822,10 +310,7 @@ def islandIntersectUvIsland(source, target, xSourceOffset, ySourceOffset):
# 1 test for source being totally inside target
for pv in source[7]:
if NEW_2_38_MATHUTILS:
p = Vector(pv)
else:
p = CopyVec(pv)
p = Vector(pv)
p.x += xSourceOffset
p.y += ySourceOffset
@@ -834,11 +319,7 @@ def islandIntersectUvIsland(source, target, xSourceOffset, ySourceOffset):
# 2 test for a part of the target being totaly inside the source.
for pv in target[7]:
if NEW_2_38_MATHUTILS:
p = Vector(pv)
else:
p = CopyVec(pv)
p = Vector(pv)
p.x -= xSourceOffset
p.y -= ySourceOffset
@@ -861,11 +342,7 @@ def testNewVecLs2DRotIsBetter(vecs, mat=-1, bestAreaSoFar = -1):
# Do this allong the way
if mat != -1:
# 2.37 depricated
if NEW_2_38_MATHUTILS:
v = vecs[i] = v*mat
else:
v = vecs[i] = VecMultMat(v, mat)
v = vecs[i] = v*mat
minx = min(minx, v.x)
maxx = max(maxx, v.x)
@@ -971,8 +448,8 @@ def optiRotateUvIsland(faces):
# Now write the vectors back to the face UV's
i = 0 # count the serialized uv/vectors
for f in faces:
f.uv = [uv for uv in uvVecs[i:len(f)+i] ]
i += len(f)
f.uv = tuple([uv for uv in uvVecs[i:len(f.v)+i] ])
i += len(f.v)
# Takes an island list and tries to find concave, hollow areas to pack smaller islands into.
@@ -1000,7 +477,7 @@ def mergeUvIslands(islandList, islandListArea):
while fIdx:
fIdx-=1
f = islandList[islandIdx][fIdx]
f.uv = [(uv[0]-minx, uv[1]-miny) for uv in f.uv]
f.uv = tuple([Vector(uv[0]-minx, uv[1]-miny) for uv in f.uv])
totFaceArea += islandListArea[islandIdx][fIdx] # Use Cached area. dont recalculate.
islandBoundsArea = w*h
efficiency = abs(islandBoundsArea - totFaceArea)
@@ -1119,26 +596,16 @@ def mergeUvIslands(islandList, islandListArea):
'''
# Move the test allong its width + SMALL_NUM
boxLeft += sourceIsland[4] + SMALL_NUM
#py_sys.stdout.write('>')
#pass
elif Intersect == 0: # No intersection?? Place it.
# Progress
removedCount +=1
Window.DrawProgressBar(0.0, 'Merged: %i islands, Ctrl to finish early.' % removedCount)
'''
if py_sys:
py_sys.stdout.write('#')
py_sys.stdout.flush()
else:
print '#'
'''
# Move faces into new island and offset
targetIsland[0].extend(sourceIsland[0])
while sourceIsland[0]:
f = sourceIsland[0].pop()
f.uv = [(uv[0]+boxLeft, uv[1]+boxBottom) for uv in f.uv]
f.uv = tuple([Vector(uv[0]+boxLeft, uv[1]+boxBottom) for uv in f.uv])
# Move edge loop into new and offset.
# targetIsland[6].extend(sourceIsland[6])
@@ -1179,19 +646,12 @@ def mergeUvIslands(islandList, islandListArea):
areaIslandIdx+=1
# Remove empty islands
# removedCount = 0
i = len(islandList)
while i:
i-=1
if not islandList[i]:
islandList.pop(i)
# removedCount+=1
islandList.pop(i) # Can increment islands removed here.
# Dont need to return anything
# if py_sys: py_sys.stdout.flush()
# print ''
# print removedCount, 'merged'
# Takes groups of faces. assumes face groups are UV groups.
def packLinkedUvs(faceGroups, faceGroupsArea, me):
@@ -1254,7 +714,7 @@ def packLinkedUvs(faceGroups, faceGroupsArea, me):
for v in newIsland[0].v:
popoffset = 0
for fIdx in xrange(len(faceUsers[v.index])):
if faceUsers[v.index][fIdx - popoffset] == newIsland[0]:
if faceUsers[v.index][fIdx - popoffset] is newIsland[0]:
faceUsers[v.index].pop(fIdx - popoffset)
faceUsersArea[v.index].pop(fIdx - popoffset)
@@ -1276,7 +736,7 @@ def packLinkedUvs(faceGroups, faceGroupsArea, me):
#faceUsers = [f for f in faceUsers[vv.index] if f != sharedFace]
fIdx = 0
for fIdx in xrange(len(faceUsers[vv.index])):
if faceUsers[vv.index][fIdx] == sharedFace:
if faceUsers[vv.index][fIdx] is sharedFace:
faceUsers[vv.index].pop(fIdx)
faceUsersArea[vv.index].pop(fIdx)
break # Can only be used once.
@@ -1291,15 +751,7 @@ def packLinkedUvs(faceGroups, faceGroupsArea, me):
else:
print '\t(empty island found, ignoring)'
#Window.DrawProgressBar(0.1, 'Found %i UV Islands' % len(islandList))
#print '\n\tFound %i UV Islands' % len(islandList)
#print '\tOptimizing Island Rotation...'
Window.DrawProgressBar(0.1, 'Optimizing Rotation for %i UV Islands' % len(islandList))
@@ -1309,9 +761,7 @@ def packLinkedUvs(faceGroups, faceGroupsArea, me):
if USER_FILL_HOLES:
Window.DrawProgressBar(0.1, 'Merging Islands...')
#print '\tMerging islands to save space ("#" == one merge):\n',
if py_sys: py_sys.stdout.flush()
Window.DrawProgressBar(0.1, 'Merging Islands (Ctrl: skip merge)...')
mergeUvIslands(islandList, islandListArea) # Modify in place
@@ -1354,7 +804,7 @@ def packLinkedUvs(faceGroups, faceGroupsArea, me):
Window.DrawProgressBar(0.7, 'Packing %i UV Islands...' % len(boxes2Pack) )
time1 = sys.time()
packWidth, packHeight, packedLs = boxPackIter(boxes2Pack)
packWidth, packHeight, packedLs = boxpack2d.boxPackIter(boxes2Pack)
# print 'Box Packing Time:', sys.time() - time1
#if len(pa ckedLs) != len(islandList):
@@ -1367,8 +817,12 @@ def packLinkedUvs(faceGroups, faceGroupsArea, me):
islandIdx = len(islandList)
# Having these here avoids devide by 0
if islandIdx:
xfactor = 1.0 / packWidth
yfactor = 1.0 / packHeight
# Maximize to uv area?? Will write a normalize function.
#xfactor = 1.0 / packWidth
#yfactor = 1.0 / packHeight
# Keep proportions.
xfactor = yfactor = 1.0 / max(packWidth, packHeight)
while islandIdx:
islandIdx -=1
@@ -1378,14 +832,11 @@ def packLinkedUvs(faceGroups, faceGroupsArea, me):
xoffset = packedLs[islandIdx][1] - islandOffsetList[islandIdx][0]
yoffset = packedLs[islandIdx][2] - islandOffsetList[islandIdx][1]
for f in islandList[islandIdx]: # Offsetting the UV's so they fit in there packed box
f.uv = [(((uv[0]+xoffset)*xfactor), ((uv[1]+yoffset)*yfactor)) for uv in f.uv]
f.uv = tuple([Vector(((uv[0]+xoffset)*xfactor), ((uv[1]+yoffset)*yfactor)) for uv in f.uv])
def VectoMat(vec):
if NEW_2_38_MATHUTILS:
a3 = Vector(vec)
else:
a3 = CopyVec(vec)
a3 = Vector(vec)
a3.normalize()
@@ -1442,11 +893,11 @@ def main():
if ob.getType() != 'Mesh':
continue
me = ob.getData()
me = ob.getData(mesh=1)
if USER_ONLY_SELECTED_FACES:
meshFaces = [f for f in me.getSelectedFaces() if len(f) > 2]
meshFaces = [f for f in me.faces if f.sel if len(f.v) > 2]
else:
meshFaces = [f for f in me.faces if len(f) > 2]
meshFaces = [f for f in me.faces if len(f.v) > 2]
if not meshFaces:
continue
@@ -1467,7 +918,7 @@ def main():
for f in meshFaces:
area = faceArea(f)
if area <= SMALL_NUM:
f.uv = [(0.0, 0.0)] * len(f)
f.uv = [(0.0, 0.0)] * len(f.v)
print 'found zero area face, removing.'
else:
@@ -1573,9 +1024,7 @@ def main():
i = len(projectVecs)
# Initialize first
bestAng = DotVecs(fvec, projectVecs[0])
# print bestAng
bestAngIdx = 0
# Cycle through the remaining, first alredy done
@@ -1609,26 +1058,25 @@ def main():
# Get the faces UV's from the projected vertex.
for f in faceProjectionGroupList[i]:
if NEW_2_38_MATHUTILS:
f.uv = [MatProj * v.co for v in f.v]
else:
f.uv = [MatMultVec(MatProj, v.co) for v in f.v]
f.uv = tuple([MatProj * v.co for v in f.v])
packLinkedUvs(faceProjectionGroupList, faceProjectionGroupListArea, me)
#print "ArchiMap time: %.2f" % (sys.time() - time1)
print "ArchiMap time: %.2f" % (sys.time() - time1)
Window.DrawProgressBar(0.9, "ArchiMap Done, time: %.2f sec." % (sys.time() - time1))
# Update and dont mess with edge data.
me.update(0, (me.edges != []), 0)
# OLD NMESH # me.update(0, (me.edges != []), 0)
Window.DrawProgressBar(1.0, "")
Window.WaitCursor(0)
Window.RedrawAll()
try:
main()
except KeyboardInterrupt:
print '\nUser Canceled.'
Draw.PupMenu('user canceled execution, unwrap aborted.')
Window.WaitCursor(0)
Window.DrawProgressBar(1.0, "")
Window.WaitCursor(0)