Mostly fixed archimap issue where "fill holes" - island filling would hang ths script.

Some optimizations and Ctrl will escape the script properly if you want to skip merging the islands.

Thanks to Melchior FRANZ for the report and debug blend
This commit is contained in:
Campbell Barton 2006-07-29 12:21:38 +00:00
parent 792114e476
commit d56de7edb7
2 changed files with 144 additions and 116 deletions

@ -27,12 +27,12 @@ packWidth, packHeight, packedLs = boxpack2d.boxPackIter(boxes2Pack)
'''
from Blender import NMesh, Window, Object, Scene
'''
def debug_(x,y,z):
ob = Object.New("Empty")
ob.loc= x,y,z
Scene.GetCurrent().link(ob)
'''
# a box packing vert
class vt:
@ -295,15 +295,14 @@ class boxList:
# 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
# At the moment we only start with 1 box so the code below will loop over 1. but thats ok.
width = height = 0.0
if boxes:
for b in boxes:
self.width = max(self.width, b.width)
self.height = max(self.height, b.height)
if width < b.width: width= b.width
if height < b.height: height= b.height
self.width= width
self.height= height
# boxArea is the total area of all boxes in the list,
# can be used with packArea() to determine waistage.
@ -326,6 +325,7 @@ class boxList:
# 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.
@ -378,7 +378,7 @@ class boxList:
# Sort boxes by area
def sortArea(self):
self.boxes.sort(lambda A, B: cmp(B.area, A.area) ) # Reverse area sort
self.boxes.sort(lambda A, B: cmp(A.area, B.area) ) # Reverse area sort
# BLENDER only
def draw(self):
@ -408,20 +408,21 @@ class boxList:
if not self.boxes:
return
packedboxes = boxList([self.boxes[0]])
packedboxes = boxList([self.boxes[-1]])
# Remove verts we KNOW cant be added to
unpackedboxes = boxList(self.boxes[1:])
unpackedboxes = self.boxes[:-1]
# Start with this box, the biggest box
boxList.packedVerts.verts.extend(packedboxes.boxes[0].v)
while unpackedboxes.boxes: # != [] - while the list of unpacked boxes is not empty.
while unpackedboxes: # != [] - while the list of unpacked boxes is not empty.
freeBoxIdx = 0
while freeBoxIdx < len(unpackedboxes.boxes):
freeBoxContext= unpackedboxes.boxes[freeBoxIdx]
freeBoxIdx = len(unpackedboxes)
while freeBoxIdx:
freeBoxIdx-=1
freeBoxContext= unpackedboxes[freeBoxIdx]
# Sort the verts with this boxes dimensions as a bias, so less poky out bits are made.
boxList.packedVerts.sortCorner(freeBoxContext.width, freeBoxContext.height)
@ -431,7 +432,7 @@ class boxList:
if baseVert.free: # != 0
# This will lock the box if its possibel
if freeBoxContext.tryVert(packedboxes, baseVert):
packedboxes.addBoxPack( unpackedboxes.boxes.pop(freeBoxIdx) ) # same as freeBoxContext. but may as well pop at the same time.
packedboxes.addBoxPack( unpackedboxes.pop(freeBoxIdx) ) # same as freeBoxContext. but may as well pop at the same time.
freeBoxIdx = -1
break

@ -57,7 +57,7 @@ USER_FILL_HOLES = None
USER_FILL_HOLES_QUALITY = None
import boxpack2d
# reload(boxpack2d) # for developing.
reload(boxpack2d) # for developing.
# Do 2 lines intersect?
@ -481,9 +481,9 @@ def mergeUvIslands(islandList, islandListArea):
# Sort by island bounding box area, smallest face area first.
# no.. chance that to most simple edge loop first.
decoratedIslandListAreaSort =decoratedIslandList[:]
decoratedIslandListAreaSort.sort(lambda A, B: cmp(A[1], B[1]))
decoratedIslandListAreaSort.sort(lambda A, B: cmp(A[3], B[3]))
# sort by efficiency, Most Efficient first.
# sort by efficiency, Least Efficient first.
decoratedIslandListEfficSort = decoratedIslandList[:]
decoratedIslandListEfficSort.sort(lambda A, B: cmp(B[2], A[2]))
@ -495,7 +495,7 @@ def mergeUvIslands(islandList, islandListArea):
# 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 quaklity
# 1 means they have the same quality
USER_FREE_SPACE_TO_TEST_QUALITY = 1 + (((100 - USER_FILL_HOLES_QUALITY)/100.0) *5)
#print 'USER_STEP_QUALITY', USER_STEP_QUALITY
@ -505,7 +505,8 @@ def mergeUvIslands(islandList, islandListArea):
areaIslandIdx = 0
ctrl = Window.Qual.CTRL
while areaIslandIdx < len(decoratedIslandListAreaSort) and (not Window.GetKeyQualifiers() & ctrl):
BREAK= False
while areaIslandIdx < len(decoratedIslandListAreaSort) and not BREAK:
sourceIsland = decoratedIslandListAreaSort[areaIslandIdx]
# Alredy packed?
@ -513,7 +514,11 @@ def mergeUvIslands(islandList, islandListArea):
areaIslandIdx+=1
else:
efficIslandIdx = 0
while efficIslandIdx < len(decoratedIslandListEfficSort):
while efficIslandIdx < len(decoratedIslandListEfficSort) and not BREAK:
if Window.GetKeyQualifiers() & ctrl:
BREAK= True
break
# Now we have 2 islands, is the efficience of the islands lowers theres an
# increasing likely hood that we can fit merge into the bigger UV island.
@ -525,110 +530,131 @@ def mergeUvIslands(islandList, islandListArea):
if sourceIsland[0] == targetIsland[0] or\
targetIsland[0] == [] or\
sourceIsland[0] == []:
efficIslandIdx+=1
continue
# ([island, totFaceArea, efficiency, islandArea, w,h])
# Waisted space on target is greater then UV bounding island area.
# if targetIsland[3] > (sourceIsland[2]) and\ #
if targetIsland[3] > (sourceIsland[1] * USER_FREE_SPACE_TO_TEST_QUALITY) and\
targetIsland[4] > sourceIsland[4] and\
targetIsland[5] > sourceIsland[5]:
not targetIsland[0] or\
not sourceIsland[0]:
pass
else:
# ([island, totFaceArea, efficiency, islandArea, w,h])
# Waisted space on target is greater then UV bounding island area.
# DEBUG # print '%.10f %.10f' % (targetIsland[3], sourceIsland[1])
# if targetIsland[3] > (sourceIsland[2]) and\ #
# 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]
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))
yIncrement = (testHeight / (blockTestYUnit * USER_STEP_QUALITY))
boxLeft = 0 # Start 1 back so we can jump into the loop.
boxBottom= 0 #-yIncrement
while boxLeft <= testWidth or boxBottom <= testHeight:
if targetIsland[3] > (sourceIsland[1] * USER_FREE_SPACE_TO_TEST_QUALITY) and\
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]
boxLeft = 0
# Distllllance 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))
yIncrement = (testHeight / (blockTestYUnit * USER_STEP_QUALITY))
xIncrement= testWidth/USER_STEP_QUALITY
yIncrement= testHeight/USER_STEP_QUALITY
# 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]
Intersect = islandIntersectUvIsland(sourceIsland, targetIsland, boxLeft, boxBottom)
boxLeft = 0 # Start 1 back so we can jump into the loop.
boxBottom= 0 #-yIncrement
if Intersect == 1: # Line intersect, dont bother with this any more
pass
##testcount= 0
if Intersect == 2: # Source inside target
'''
We have an intersection, if we are inside the target
then move us 1 whole width accross,
Its possible this is a bad idea since 2 skinny Angular faces
could join without 1 whole move, but its a lot more optimal to speed this up
since we have alredy tested for it.
while boxBottom <= testHeight:
# Should we use this? - not needed for now.
#if Window.GetKeyQualifiers() & ctrl:
# BREAK= True
# break
It gives about 10% speedup with minimal errors.
'''
# Move the test allong its width + SMALL_NUM
boxLeft += sourceIsland[4] + SMALL_NUM
elif Intersect == 0: # No intersection?? Place it.
# Progress
removedCount +=1
Window.DrawProgressBar(0.0, 'Merged: %i islands, Ctrl to finish early.' % removedCount)
##testcount+=1
#print 'Testing intersect'
Intersect = islandIntersectUvIsland(sourceIsland, targetIsland, boxLeft, boxBottom)
#print 'Done', Intersect
if Intersect == 1: # Line intersect, dont bother with this any more
pass
# Move faces into new island and offset
targetIsland[0].extend(sourceIsland[0])
while sourceIsland[0]:
f = sourceIsland[0].pop()
f.uv = [Vector(uv[0]+boxLeft, uv[1]+boxBottom) for uv in f.uv]
if Intersect == 2: # Source inside target
'''
We have an intersection, if we are inside the target
then move us 1 whole width accross,
Its possible this is a bad idea since 2 skinny Angular faces
could join without 1 whole move, but its a lot more optimal to speed this up
since we have alredy tested for it.
It gives about 10% speedup with minimal errors.
'''
#print 'ass'
# Move the test allong its width + SMALL_NUM
#boxLeft += sourceIsland[4] + SMALL_NUM
boxLeft += sourceIsland[4]
elif Intersect == 0: # No intersection?? Place it.
# Progress
removedCount +=1
Window.DrawProgressBar(0.0, 'Merged: %i islands, Ctrl to finish early.' % removedCount)
# Move faces into new island and offset
targetIsland[0].extend(sourceIsland[0])
for f in sourceIsland[0]:
f.uv = [Vector(uv[0]+boxLeft, uv[1]+boxBottom) for uv in f.uv]
sourceIsland[0][:] = [] # Empty
# Move edge loop into new and offset.
# targetIsland[6].extend(sourceIsland[6])
while sourceIsland[6]:
e = sourceIsland[6].pop()
targetIsland[6].append(\
((e[0][0]+boxLeft, e[0][1]+boxBottom),\
(e[1][0]+boxLeft, e[1][1]+boxBottom), e[2])\
)
# Sort by edge length, reverse so biggest are first.
targetIsland[6].sort(lambda B,A: cmp(A[2], B[2] ))
targetIsland[7].extend(sourceIsland[7])
while sourceIsland[7]:
p = sourceIsland[7].pop()
p.x += boxLeft; p.y += boxBottom
# Move edge loop into new and offset.
# targetIsland[6].extend(sourceIsland[6])
#while sourceIsland[6]:
targetIsland[6].extend( [ (\
((e[0][0]+boxLeft, e[0][1]+boxBottom),\
(e[1][0]+boxLeft, e[1][1]+boxBottom), e[2])\
) for e in sourceIsland[6] ] )
sourceIsland[6][:] = [] # Empty
# Sort by edge length, reverse so biggest are first.
targetIsland[6].sort(lambda B,A: cmp(A[2], B[2] ))
targetIsland[7].extend(sourceIsland[7])
for p in sourceIsland[7]:
p.x += boxLeft; p.y += boxBottom
sourceIsland[7][:] = []
# Decrement the 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 is anyone wants to know
break
# Decrement the 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 is anyone wants to know
break
# INCREMENR NEXT LOCATION
if boxLeft > testWidth:
boxBottom += yIncrement
boxLeft = 0.0
else:
boxLeft += xIncrement
# INCREMENR NEXT LOCATION
if boxLeft > testWidth:
boxBottom += yIncrement
boxLeft = 0.0
else:
boxLeft += xIncrement
##print testcount
efficIslandIdx+=1
areaIslandIdx+=1
@ -1129,8 +1155,6 @@ def main():
packIslands(islandList, islandListArea)
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.
# OLD NMESH # me.update(0, (me.edges != []), 0)
@ -1140,6 +1164,9 @@ def main():
Window.DrawProgressBar(0.9, "Box Packing for all objects...")
packIslands(collected_islandList, collected_islandListArea)
print "ArchiMap time: %.2f" % (sys.time() - time1)
Window.DrawProgressBar(0.9, "ArchiMap Done, time: %.2f sec." % (sys.time() - time1))
Window.DrawProgressBar(1.0, "")
Window.WaitCursor(0)
Window.RedrawAll()