[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [24281] trunk/blender/release/scripts/io/ uvcalc_smart_project.py: script copied from 2.4x with no changes

Campbell Barton ideasman42 at gmail.com
Tue Nov 3 18:47:44 CET 2009


Revision: 24281
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=24281
Author:   campbellbarton
Date:     2009-11-03 18:47:44 +0100 (Tue, 03 Nov 2009)

Log Message:
-----------
script copied from 2.4x with no changes

Added Paths:
-----------
    trunk/blender/release/scripts/io/uvcalc_smart_project.py

Copied: trunk/blender/release/scripts/io/uvcalc_smart_project.py (from rev 24280, branches/blender2.4/release/scripts/uvcalc_smart_project.py)
===================================================================
--- trunk/blender/release/scripts/io/uvcalc_smart_project.py	                        (rev 0)
+++ trunk/blender/release/scripts/io/uvcalc_smart_project.py	2009-11-03 17:47:44 UTC (rev 24281)
@@ -0,0 +1,1132 @@
+#!BPY
+
+""" Registration info for Blender menus: <- these words are ignored
+Name: 'Unwrap (smart projections)'
+Blender: 240
+Group: 'UVCalculation'
+Tooltip: 'UV Unwrap mesh faces for all select mesh objects'
+"""
+
+
+__author__ = "Campbell Barton"
+__url__ = ("blender", "blenderartists.org")
+__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 used unwrap
+selected faces, or all faces.
+"""
+
+# -------------------------------------------------------------------------- 
+# Smart Projection UV Projection Unwrapper v1.1 by Campbell Barton (AKA Ideasman) 
+# -------------------------------------------------------------------------- 
+# ***** 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; either version 2 
+# of the License, or (at your option) any later version. 
+# 
+# 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. 
+# 
+# ***** END GPL LICENCE BLOCK ***** 
+# -------------------------------------------------------------------------- 
+
+
+from Blender import Object, Draw, Window, sys, Mesh, Geometry
+from Blender.Mathutils import Matrix, Vector, RotationMatrix
+import bpy
+from math import cos
+
+DEG_TO_RAD = 0.017453292519943295 # pi/180.0
+SMALL_NUM = 0.000000001
+BIG_NUM = 1e15
+
+global USER_FILL_HOLES
+global USER_FILL_HOLES_QUALITY
+USER_FILL_HOLES = None
+USER_FILL_HOLES_QUALITY = None
+
+dict_matrix = {}
+
+def pointInTri2D(v, v1, v2, v3):
+	global dict_matrix
+	
+	key = v1.x, v1.y, v2.x, v2.y, v3.x, v3.y
+	
+	# Commented because its slower to do teh bounds check, we should realy cache the bounds info for each face.
+	'''
+	# BOUNDS CHECK
+	xmin= 1000000
+	ymin= 1000000
+	
+	xmax= -1000000
+	ymax= -1000000
+	
+	for i in (0,2,4):
+		x= key[i]
+		y= key[i+1]
+		
+		if xmax<x:	xmax= x
+		if ymax<y:	ymax= y
+		if xmin>x:	xmin= x
+		if ymin>y:	ymin= y	
+	
+	x= v.x
+	y= v.y
+	
+	if x<xmin or x>xmax or y < ymin or y > ymax:
+		return False
+	# Done with bounds check
+	'''
+	try:
+		mtx = dict_matrix[key]
+		if not mtx:
+			return False
+	except:
+		side1 = v2 - v1
+		side2 = v3 - v1
+		
+		nor = side1.cross(side2)
+		
+		l1 = [side1[0], side1[1], side1[2]]
+		l2 = [side2[0], side2[1], side2[2]]
+		l3 = [nor[0], nor[1], nor[2]]
+		
+		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.
+		if not mtx.determinant():
+			dict_matrix[key] = None
+			return False
+		
+		mtx.invert()
+		
+		dict_matrix[key] = mtx
+	
+	uvw = (v - v1) * mtx
+	return 0 <= uvw[0] and 0 <= uvw[1] and uvw[0] + uvw[1] <= 1
+
+	
+def boundsIsland(faces):
+	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
+	
+	return minx, miny, maxx, maxy
+
+"""
+def boundsEdgeLoop(edges):
+	minx = maxx = edges[0][0] # Set initial bounds.
+	miny = maxy = edges[0][1]
+	# print len(faces), minx, maxx, miny , maxy
+	for ed in edges:
+		for pt in ed:
+			print 'ass'
+			x= pt[0]
+			y= pt[1]
+			if x<minx: x= minx
+			if y<miny: y= miny
+			if x>maxx: x= maxx
+			if y>maxy: y= maxy
+	
+	return minx, miny, maxx, maxy
+"""
+
+# Turns the islands into a list of unpordered edges (Non internal)
+# Onlt for UV's
+# only returns outline edges for intersection tests. and unique points.
+
+def island2Edge(island):
+	
+	# Vert index edges
+	edges = {}
+	
+	unique_points= {}
+	
+	for f in island:
+		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
+			else:		
+				i1= vIdx;	i2= vIdx-1
+			
+			try:	edges[ f_uvkey[i1], f_uvkey[i2] ] *= 0 # sets eny edge with more then 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.iteritems() 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]))
+	
+	# Its okay to leave the length in there.
+	#for e in length_sorted_edges:
+	#	e.pop(2)
+	
+	# return edges and unique points
+	return length_sorted_edges, [v.__copy__().resize3D() for v in unique_points.itervalues()]
+	
+# ========================= NOT WORKING????
+# Find if a points inside an edge loop, un-orderd.
+# pt is and x/y
+# edges are a non ordered loop of edges.
+# #offsets are the edge x and y offset.
+"""
+def pointInEdges(pt, edges):
+	#
+	x1 = pt[0] 
+	y1 = pt[1]
+	
+	# Point to the left of this line.
+	x2 = -100000
+	y2 = -10000
+	intersectCount = 0
+	for ed in edges:
+		xi, yi = lineIntersection2D(x1,y1, x2,y2, ed[0][0], ed[0][1], ed[1][0], ed[1][1])
+		if xi != None: # Is there an intersection.
+			intersectCount+=1
+	
+	return intersectCount % 2
+"""
+
+def pointInIsland(pt, island):
+	vec1 = Vector(); vec2 = Vector(); vec3 = Vector()	
+	for f in island:
+		vec1.x, vec1.y = f.uv[0]
+		vec2.x, vec2.y = f.uv[1]
+		vec3.x, vec3.y = f.uv[2]
+
+		if pointInTri2D(pt, vec1, vec2, vec3):
+			return True
+		
+		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]			
+			if pointInTri2D(pt, vec1, vec2, vec3):
+				return True
+	return False
+
+
+# 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
+	edgeLoopsTarget = target[6]
+	
+	# Edge intersect test	
+	for ed in edgeLoopsSource:
+		for seg in edgeLoopsTarget:
+			i = Geometry.LineIntersect2D(\
+			seg[0], seg[1], SourceOffset+ed[0], SourceOffset+ed[1])
+			if i:
+				return 1 # LINE INTERSECTION
+	
+	# 1 test for source being totally inside target
+	SourceOffset.resize3D()
+	for pv in source[7]:
+		if pointInIsland(pv+SourceOffset, target[0]):
+			return 2 # SOURCE INSIDE TARGET
+	
+	# 2 test for a part of the target being totaly inside the source.
+	for pv in target[7]:
+		if pointInIsland(pv-SourceOffset, source[0]):
+			return 3 # PART OF TARGET INSIDE SOURCE.
+
+	return 0 # NO INTERSECTION
+
+
+
+
+# Returns the X/y Bounds of a list of vectors.
+def testNewVecLs2DRotIsBetter(vecs, mat=-1, bestAreaSoFar = -1):
+	
+	# UV's will never extend this far.
+	minx = miny = BIG_NUM
+	maxx = maxy = -BIG_NUM
+	
+	for i, v in enumerate(vecs):
+		
+		# Do this allong the way
+		if mat != -1:
+			v = vecs[i] = v*mat
+			x= v.x
+			y= v.y
+			if x<minx: minx= x
+			if y<miny: miny= y
+			if x>maxx: maxx= x
+			if y>maxy: maxy= y
+		
+		# Spesific to this algo, bail out if we get bigger then the current area
+		if bestAreaSoFar != -1 and (maxx-minx) * (maxy-miny) > bestAreaSoFar:
+			return (BIG_NUM, None), None
+	w = maxx-minx
+	h = maxy-miny
+	return (w*h, w,h), vecs # Area, vecs
+	
+# Takes a list of faces that make up a UV island and rotate
+# until they optimally fit inside a square.
+ROTMAT_2D_POS_90D = RotationMatrix( 90, 2)
+ROTMAT_2D_POS_45D = RotationMatrix( 45, 2)
+
+RotMatStepRotation = []
+rot_angle = 22.5 #45.0/2
+while rot_angle > 0.1:
+	RotMatStepRotation.append([\
+	 RotationMatrix( rot_angle, 2),\
+	 RotationMatrix( -rot_angle, 2)])
+	
+	rot_angle = rot_angle/2.0
+	
+
+def optiRotateUvIsland(faces):
+	global currentArea
+	
+	# Bestfit Rotation
+	def best2dRotation(uvVecs, MAT1, MAT2):
+		global currentArea
+		
+		newAreaPos, newfaceProjectionGroupListPos =\
+		testNewVecLs2DRotIsBetter(uvVecs[:], MAT1, currentArea[0])
+		
+		
+		# Why do I use newpos here? May as well give the best area to date for an early bailout
+		# some slight speed increase in this.
+		# If the new rotation is smaller then the existing, we can 
+		# avoid copying a list and overwrite the old, crappy one.
+		
+		if newAreaPos[0] < currentArea[0]:
+			newAreaNeg, newfaceProjectionGroupListNeg =\
+			testNewVecLs2DRotIsBetter(uvVecs, MAT2, newAreaPos[0])  # Reuse the old bigger list.
+		else:
+			newAreaNeg, newfaceProjectionGroupListNeg =\
+			testNewVecLs2DRotIsBetter(uvVecs[:], MAT2, currentArea[0])  # Cant reuse, make a copy.
+		
+		
+		# Now from the 3 options we need to discover which to use
+		# we have cerrentArea/newAreaPos/newAreaNeg
+		bestArea = min(currentArea[0], newAreaPos[0], newAreaNeg[0])
+		
+		if currentArea[0] == bestArea:
+			return uvVecs
+		elif newAreaPos[0] == bestArea:
+			uvVecs = newfaceProjectionGroupListPos
+			currentArea = newAreaPos		
+		elif newAreaNeg[0] == bestArea:
+			uvVecs = newfaceProjectionGroupListNeg
+			currentArea = newAreaNeg
+		
+		return uvVecs
+		
+	
+	# Serialized UV coords to Vectors
+	uvVecs = [uv for f in faces  for uv in f.uv]
+	
+	# Theres a small enough number of these to hard code it
+	# rather then a loop.
+	
+	# Will not modify anything
+	currentArea, dummy =\
+	testNewVecLs2DRotIsBetter(uvVecs)
+	
+	
+	# Try a 45d rotation
+	newAreaPos, newfaceProjectionGroupListPos = testNewVecLs2DRotIsBetter(uvVecs[:], ROTMAT_2D_POS_45D, currentArea[0])
+	
+	if newAreaPos[0] < currentArea[0]:
+		uvVecs = newfaceProjectionGroupListPos
+		currentArea = newAreaPos
+	# 45d done
+	
+	# Testcase different rotations and find the onfe that best fits in a square

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list