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) decoratedIslandList = [] islandIdx = len(islandList) while islandIdx: islandIdx -= 1 minx, miny, maxx, maxy = boundsIsland(islandList[islandIdx]) w, h = maxx - minx, maxy - miny totFaceArea = 0 offset = Vector(minx, miny) for f in islandList[islandIdx]: for uv in f.uv: uv -= offset totFaceArea += f.area 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 ]) # Sort by island bounding box area, smallest face area first. # no.. chance that to most simple edge loop first. decoratedIslandListAreaSort = decoratedIslandList[:] try: decoratedIslandListAreaSort.sort(key=lambda A: A[3]) except: decoratedIslandListAreaSort.sort(lambda A, B: cmp(A[3], B[3])) # sort by efficiency, Least Efficient first. decoratedIslandListEfficSort = decoratedIslandList[:] # decoratedIslandListEfficSort.sort(lambda A, B: cmp(B[2], A[2])) try: decoratedIslandListEfficSort.sort(key=lambda A: -A[2]) except: decoratedIslandListEfficSort.sort(lambda A, B: cmp(B[2], 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 # 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) #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 while areaIslandIdx < len(decoratedIslandListAreaSort) and not BREAK: sourceIsland = decoratedIslandListAreaSort[areaIslandIdx] # Alredy packed? if not sourceIsland[0]: areaIslandIdx += 1 else: efficIslandIdx = 0 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. # this ensures a tight fit. # Just use figures we have about user/unused area to see if they might fit. targetIsland = decoratedIslandListEfficSort[efficIslandIdx] if sourceIsland[0] == targetIsland[0] or\ 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. # if targetIsland[3] > (sourceIsland[2]) and\ # # print USER_FREE_SPACE_TO_TEST_QUALITY, 'ass' if targetIsland[2] > (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 / 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] boxLeft = 0 # Start 1 back so we can jump into the loop. boxBottom = 0 #-yIncrement ##testcount= 0 while boxBottom <= testHeight: # Should we use this? - not needed for now. #if Window.GetKeyQualifiers() & ctrl: # BREAK= True # break ##testcount+=1 #print 'Testing intersect' Intersect = islandIntersectUvIsland( sourceIsland, targetIsland, Vector(boxLeft, boxBottom)) #print 'Done', Intersect if Intersect == 1: # Line intersect, dont bother with this any more pass 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]) offset = Vector(boxLeft, boxBottom) for f in sourceIsland[0]: for uv in f.uv: uv += offset 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] ] ) 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])) targetIsland[7].extend(sourceIsland[7]) offset = Vector(boxLeft, boxBottom, 0) for p in sourceIsland[7]: p += offset 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 if anyone wants to know break # INCREMENR NEXT LOCATION if boxLeft > testWidth: boxBottom += yIncrement boxLeft = 0.0 else: boxLeft += xIncrement ##print testcount efficIslandIdx += 1 areaIslandIdx += 1 # Remove empty islands i = len(islandList) while i: i -= 1 if not islandList[i]: del islandList[i] # Can increment islands removed here.
def main(): scn = bpy.data.scenes.active ob = scn.objects.active if not ob or ob.type != 'Mesh': return is_editmode = Window.EditMode() if is_editmode: Window.EditMode(0) mousedown_wait() # so the menu items clicking dosnt trigger the mouseclick Window.DrawProgressBar(0.0, '') Window.DrawProgressBar(0.1, '(1 of 3) Click on a face corner') # wait for a click mouse_buttons = Window.GetMouseButtons() while not mouse_buttons & LMB: sys.sleep(10) mouse_buttons = Window.GetMouseButtons() # Allow for RMB cancel if mouse_buttons & RMB: return while mouse_buttons & LMB: sys.sleep(10) mouse_buttons = Window.GetMouseButtons() Window.DrawProgressBar(0.2, '(2 of 3 ) Click confirms the U coords') mousedown_wait() obmat = ob.matrixWorld screen_x, screen_y = Window.GetMouseCoords() mouseInView, OriginA, DirectionA = mouseViewRay(screen_x, screen_y, obmat) if not mouseInView or not OriginA: return me = ob.getData(mesh=1) # Get the face under the mouse face_click, isect, side = BPyMesh.pickMeshRayFace(me, OriginA, DirectionA) if not face_click: return proj_z_component = face_click.no if not face_click: return # Find the face vertex thats closest to the mouse, # this vert will be used as the corner to map from. best_v = None best_length = 10000000 vi1 = None for i, v in enumerate(face_click.v): l = (v.co - isect).length if l < best_length: best_v = v best_length = l vi1 = i # now get the 2 edges in the face that connect to v # we can work it out fairly easerly if len(face_click) == 4: if vi1 == 0: vi2, vi3 = 3, 1 elif vi1 == 1: vi2, vi3 = 0, 2 elif vi1 == 2: vi2, vi3 = 1, 3 elif vi1 == 3: vi2, vi3 = 2, 0 else: if vi1 == 0: vi2, vi3 = 2, 1 elif vi1 == 1: vi2, vi3 = 0, 2 elif vi1 == 2: vi2, vi3 = 1, 0 face_corner_main = face_click.v[vi1].co face_corner_a = face_click.v[vi2].co face_corner_b = face_click.v[vi3].co line_a_len = (face_corner_a - face_corner_main).length line_b_len = (face_corner_b - face_corner_main).length orig_cursor = Window.GetCursorPos() Window.SetCursorPos(face_corner_main.x, face_corner_main.y, face_corner_main.z) SHIFT = Window.Qual.SHIFT MODE = 0 # firstclick, 1, secondclick mouse_buttons = Window.GetMouseButtons() project_mat = Matrix([0, 0, 0], [0, 0, 0], [0, 0, 0]) def get_face_coords(f): f_uv = f.uv return [(v.co - face_corner_main, f_uv[i]) for i, v in enumerate(f.v)] if me.faceUV == False: me.faceUV = True coords = [(co, uv) for f in me.faces if f.sel for co, uv in get_face_coords(f)] coords_orig = [uv.copy() for co, uv in coords] USE_MODIFIER = using_modifier(ob) while 1: if mouse_buttons & LMB: if MODE == 0: mousedown_wait() Window.DrawProgressBar( 0.8, '(3 of 3 ) Click confirms the V coords') MODE = 1 # second click # Se we cont continually set the length and get float error proj_y_component_orig = proj_y_component.copy() else: break elif mouse_buttons & RMB: # Restore old uvs for i, uv_orig in enumerate(coords_orig): coords[i][1][:] = uv_orig break mouse_buttons = Window.GetMouseButtons() screen_x, screen_y = Window.GetMouseCoords() mouseInView, OriginA, DirectionA = mouseViewRay( screen_x, screen_y, obmat) if not mouseInView: continue # Do a ray tri intersection, not clipped by the tri new_isect = Intersect(face_corner_main, face_corner_a, face_corner_b, DirectionA, OriginA, False) new_isect_alt = new_isect + DirectionA * 0.0001 # The distance from the mouse cursor ray vector to the edge line_isect_a_pair = LineIntersect(new_isect, new_isect_alt, face_corner_main, face_corner_a) line_isect_b_pair = LineIntersect(new_isect, new_isect_alt, face_corner_main, face_corner_b) # SHIFT to flip the axis. is_shift = Window.GetKeyQualifiers() & SHIFT if MODE == 0: line_dist_a = (line_isect_a_pair[0] - line_isect_a_pair[1]).length line_dist_b = (line_isect_b_pair[0] - line_isect_b_pair[1]).length if line_dist_a < line_dist_b: proj_x_component = face_corner_a - face_corner_main y_axis_length = line_b_len x_axis_length = (line_isect_a_pair[1] - face_corner_main).length else: proj_x_component = face_corner_b - face_corner_main y_axis_length = line_a_len x_axis_length = (line_isect_b_pair[1] - face_corner_main).length proj_y_component = proj_x_component.cross(proj_z_component) proj_y_component.length = 1 / y_axis_length proj_x_component.length = 1 / x_axis_length if is_shift: proj_x_component.negate() else: proj_y_component[:] = proj_y_component_orig if line_dist_a < line_dist_b: proj_y_component.length = 1 / (line_isect_a_pair[1] - new_isect).length else: proj_y_component.length = 1 / (line_isect_b_pair[1] - new_isect).length if is_shift: proj_y_component.negate() # Use the existing matrix to make a new 3x3 projecton matrix project_mat[0][:] = -proj_y_component project_mat[1][:] = -proj_x_component project_mat[2][:] = proj_z_component # Apply the projection matrix for proj_co, uv in coords: uv[:] = (project_mat * proj_co)[0:2] if USE_MODIFIER: me.update() Window.Redraw(Window.Types.VIEW3D) Window.SetCursorPos(*orig_cursor) if is_editmode: Window.EditMode(1) Window.RedrawAll()
ROTATE_X90.val,\ IMAGE_SEARCH.val,\ POLYGROUPS.val ) Window.WaitCursor(0) def load_obj_ui_batch(file): load_obj_ui(file, True) DEBUG = False if __name__ == '__main__' and not DEBUG: if os and Window.GetKeyQualifiers() & Window.Qual.SHIFT: Window.FileSelector(load_obj_ui_batch, 'Import OBJ Dir', '') else: Window.FileSelector(load_obj_ui, 'Import a Wavefront OBJ', '*.obj') # For testing compatibility ''' else: # DEBUG ONLY TIME= sys.time() DIR = '/fe/obj' import os print 'Searching for files' def fileList(path): for dirpath, dirnames, filenames in os.walk(path): for filename in filenames:
def vertexGradientPick(ob, MODE): #MODE 0 == VWEIGHT, 1 == VCOL me = ob.getData(mesh=1) if not me.faceUV: me.faceUV = True Window.DrawProgressBar(0.0, '') mousedown_wait() if MODE == 0: act_group = me.activeGroup if act_group == None: mousedown_wait() Draw.PupMenu('Error, mesh has no active group.') return # Loop until click Window.DrawProgressBar(0.25, 'Click to set gradient start') mouseup() obmat = ob.matrixWorld screen_x, screen_y = Window.GetMouseCoords() mouseInView, OriginA, DirectionA = mouseViewRay(screen_x, screen_y, obmat) if not mouseInView or not OriginA: return # get the mouse weight if MODE == 0: pickValA = BPyMesh.pickMeshGroupWeight(me, act_group, OriginA, DirectionA) if MODE == 1: pickValA = BPyMesh.pickMeshGroupVCol(me, OriginA, DirectionA) Window.DrawProgressBar(0.75, 'Click to set gradient end') mouseup() TOALPHA = Window.GetKeyQualifiers() & Window.Qual.SHIFT screen_x, screen_y = Window.GetMouseCoords() mouseInView, OriginB, DirectionB = mouseViewRay(screen_x, screen_y, obmat) if not mouseInView or not OriginB: return if not TOALPHA: # Only get a second opaque value if we are not blending to alpha if MODE == 0: pickValB = BPyMesh.pickMeshGroupWeight(me, act_group, OriginB, DirectionB) else: pickValB = BPyMesh.pickMeshGroupVCol(me, OriginB, DirectionB) else: if MODE == 0: pickValB = 0.0 else: pickValB = [0.0, 0.0, 0.0] # Dummy value # Neither points touched a face if pickValA == pickValB == None: return # clicking on 1 non face is fine. just set the weight to 0.0 if pickValA == None: pickValA = 0.0 # swap A/B OriginA, OriginB = OriginB, OriginA DirectionA, DirectionB = DirectionB, DirectionA pickValA, pickValB = pickValA, pickValB TOALPHA = True if pickValB == None: pickValB = 0.0 TOALPHA = True # set up 2 lines so we can measure their distances and calc the gradient # make a line 90d to the grad in screenspace. if (OriginA - OriginB ).length <= eps: # Persp view. same origin different direction cross_grad = DirectionA.cross(DirectionB) ORTHO = False else: # Ortho - Same direction, different origin cross_grad = DirectionA.cross(OriginA - OriginB) ORTHO = True cross_grad.normalize() cross_grad = cross_grad * 100 lineA = (OriginA, OriginA + (DirectionA * 100)) lineB = (OriginB, OriginB + (DirectionB * 100)) if not ORTHO: line_angle = AngleBetweenVecs(lineA[1], lineB[1]) / 2 line_mid = (lineA[1] + lineB[1]) * 0.5 VSEL = [False] * (len(me.verts)) # Get the selected faces and apply the selection to the verts. for f in me.faces: if f.sel: for v in f.v: VSEL[v.index] = True groupNames, vWeightDict = BPyMesh.meshWeight2Dict(me) def grad_weight_from_co(v): ''' Takes a vert and retuens its gradient radio between A and B ''' if not VSEL[v.index]: # Not bart of a selected face? return None, None v_co = v.co # make a line 90d to the 2 lines the user clicked. vert_line = (v_co - cross_grad, v_co + cross_grad) xA = LineIntersect(vert_line[0], vert_line[1], lineA[0], lineA[1]) xB = LineIntersect(vert_line[0], vert_line[1], lineB[0], lineB[1]) if not xA or not xB: # Should never happen but support it anyhow return None, None wA = (xA[0] - xA[1]).length wB = (xB[0] - xB[1]).length wTot = wA + wB if not wTot: # lines are on the same point. return None, None ''' Get the length of the line between both intersections on the 2x view lines. if the dist between lineA+VertLine and lineB+VertLine is greater then the lenth between lineA and lineB intersection points, it means that the verts are not inbetween the 2 lines. ''' lineAB_length = (xA[1] - xB[1]).length # normalzie wA = wA / wTot wB = wB / wTot if ORTHO: # Con only use line length method with parelelle lines if wTot > lineAB_length + eps: # vert is outside the range on 1 side. see what side of the grad if wA > wB: wA, wB = 1.0, 0.0 else: wA, wB = 0.0, 1.0 else: # PERSP, lineA[0] is the same origin as lineB[0] # Either xA[0] or xB[0] can be used instead of a possible x_mid between the 2 # as long as the point is inbetween lineA and lineB it dosent matter. a = AngleBetweenVecs(lineA[0] - xA[0], line_mid) if a > line_angle: # vert is outside the range on 1 side. see what side of the grad if wA > wB: wA, wB = 1.0, 0.0 else: wA, wB = 0.0, 1.0 return wA, wB grad_weights = [grad_weight_from_co(v) for v in me.verts] if MODE == 0: for v in me.verts: i = v.index if VSEL[i]: wA, wB = grad_weights[i] if wA != None: # and wB if TOALPHA: # Do alpha by using the exiting weight for try: pickValB = vWeightDict[i][act_group] except: pickValB = 0.0 # The weights not there? assume zero # Mix2 2 opaque weights vWeightDict[i][act_group] = pickValB * wA + pickValA * wB else: # MODE==1 VCol for f in me.faces: if f.sel: f_v = f.v for i in xrange(len(f_v)): v = f_v[i] wA, wB = grad_weights[v.index] c = f.col[i] if TOALPHA: pickValB = c.r, c.g, c.b c.r = int(pickValB[0] * wA + pickValA[0] * wB) c.g = int(pickValB[1] * wA + pickValA[1] * wB) c.b = int(pickValB[2] * wA + pickValA[2] * wB) # Copy weights back to the mesh. BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict) Window.DrawProgressBar(1.0, '')
def eventHandler(event, value): """ General GUI event handler. @param event: Event type. @param value: Value of the event. """ global G if event == Draw.WHEELDOWNMOUSE: setZoom(getWMCoords(), G.zoom * (1.0 - ZOOM_DELTA)) elif event == Draw.WHEELUPMOUSE: setZoom(getWMCoords(), G.zoom * (1.0 + ZOOM_DELTA)) elif event == Draw.MIDDLEMOUSE: if value: G.mousepos = Window.GetMouseCoords() else: G.mousepos = None elif event == Draw.MOUSEX or event == Draw.MOUSEY: mouseButs = Window.GetMouseButtons() if (mouseButs & Draw.MIDDLEMOUSE) and (G.mousepos is not None): nx, ny = Window.GetMouseCoords() dx, dy = nx - G.mousepos[0], ny - G.mousepos[1] G.mousepos = (nx, ny) G.imgpos = [int(G.imgpos[0] + dx), int(G.imgpos[1] + dy)] Draw.Redraw(1) elif G.mode == MODE_ADD: Draw.Redraw(1) elif G.mode == MODE_GRAB: G.havebupclik = True nx, ny = Window.GetMouseCoords() dx, dy = (nx - G.grabpos[0]) / G.zoom, (ny - G.grabpos[1]) / G.zoom G.grabpos = [nx, ny] def translate(x): name = x.getName() if G.coordmap.has_key(name): c = G.coordmap[name] G.coordmap[name] = (c[0] + dx, c[1] + dy) map(translate, G.selection) ## autocalibration.. gets stuck some times.. #if G.last_camera: # calibrate(G.last_camera) Draw.Redraw(1) elif (event == Draw.LEFTMOUSE) or (event == Draw.RETKEY): if (G.mode == MODE_ADD) and (value == 1): x, y = map(int, getWMCoords()) x -= 10 y += 10 G.coordmap[G.curempty.getName()] = wc2ic((x, y)) G.mode = MODE_NORMAL Draw.Redraw(1) elif (G.mode == MODE_GRAB) and (value == 1): G.mode = MODE_NORMAL Draw.Redraw(1) elif (event == Draw.RIGHTMOUSE) and (value == 1): if G.mode == MODE_NORMAL: xi, yi = wc2ic(getWMCoords()) closest = None for (emptyname, coord) in G.coordmap.items(): dist = math.sqrt((coord[0] - xi)**2 + (coord[1] - yi)**2) * G.zoom if (closest == None) or (dist < closest[0]): closest = (dist, emptyname) if closest[0] < MAX_SELECT_DIST: obj = Object.Get(closest[1]) kq = Window.GetKeyQualifiers() if (kq & Window.Qual.LSHIFT) or (kq & Window.Qual.RSHIFT): obj.select(True) else: map(lambda x: x.select(False), G.selection) obj.select(True) Window.RedrawAll() elif (event == Draw.AKEY) and (value == 1): if G.mode == MODE_NORMAL: someSelected = False for (emptyname, coord) in G.coordmap.items(): if Object.Get(emptyname).isSelected(): someSelected = True break newselect = (someSelected == False) map(lambda x: Object.Get(x[0]).select(newselect), G.coordmap.items()) Window.RedrawAll() elif (event == Draw.GKEY) and (value == 1): if G.mode == MODE_NORMAL: G.mode = MODE_GRAB G.grabpos = Window.GetMouseCoords() Draw.Redraw(1) elif event == Draw.UPARROWKEY and value == 1: p = Window.GetMouseCoords() Window.SetMouseCoords(p[0], p[1] + 1) elif event == Draw.DOWNARROWKEY and value == 1: p = Window.GetMouseCoords() Window.SetMouseCoords(p[0], p[1] - 1) elif event == Draw.LEFTARROWKEY and value == 1: p = Window.GetMouseCoords() Window.SetMouseCoords(p[0] - 1, p[1]) elif event == Draw.RIGHTARROWKEY and value == 1: p = Window.GetMouseCoords() Window.SetMouseCoords(p[0] + 1, p[1]) elif event == Draw.XKEY and value == 1: if len(G.selection) > 0: result = Draw.PupMenu('OK?%t|Erase selected') if result == 1: buttonEventHandler(BUTTON_DELETE) elif event == Draw.SPACEKEY and value == 1: if (G.curempty is not None) and not (G.coordmap.has_key( G.curempty.getName())): buttonEventHandler(BUTTON_ADD) elif event == Draw.ZKEY and value == 1: x, y, w, h = getWinRect() setZoom((w / 2, h / 2), 1.0) elif event == Draw.RKEY and value == 1: Draw.Redraw(1)