| 
									
										
										
										
											2011-03-13 06:02:20 +00:00
										 |  |  | # ##### BEGIN GPL LICENSE BLOCK ##### | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | # | 
					
						
							| 
									
										
										
										
											2011-03-13 06:02:20 +00:00
										 |  |  | #  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. | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | # | 
					
						
							| 
									
										
										
										
											2011-03-13 06:02:20 +00:00
										 |  |  | #  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. | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | # | 
					
						
							| 
									
										
										
										
											2011-03-13 06:02:20 +00:00
										 |  |  | #  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | # | 
					
						
							| 
									
										
										
										
											2011-03-13 06:02:20 +00:00
										 |  |  | # ##### END GPL LICENSE BLOCK ##### | 
					
						
							| 
									
										
										
										
											2009-11-03 17:47:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-21 17:17:51 +00:00
										 |  |  | # TODO <pep8 compliant> | 
					
						
							| 
									
										
										
										
											2009-11-03 17:47:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-25 11:07:05 +11:00
										 |  |  | from mathutils import ( | 
					
						
							|  |  |  |     Matrix, | 
					
						
							|  |  |  |     Vector, | 
					
						
							|  |  |  |     geometry, | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2009-11-03 17:47:44 +00:00
										 |  |  | import bpy | 
					
						
							| 
									
										
										
										
											2011-08-12 06:57:00 +00:00
										 |  |  | from bpy.types import Operator | 
					
						
							| 
									
										
										
										
											2009-11-03 17:47:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  | DEG_TO_RAD = 0.017453292519943295  # pi/180.0 | 
					
						
							| 
									
										
										
										
											2016-04-20 11:49:14 +10:00
										 |  |  | # see bugs: | 
					
						
							|  |  |  | # - T31598 (when too small). | 
					
						
							|  |  |  | # - T48086 (when too big). | 
					
						
							|  |  |  | SMALL_NUM = 1e-12 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-03 17:47:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | global USER_FILL_HOLES | 
					
						
							|  |  |  | global USER_FILL_HOLES_QUALITY | 
					
						
							|  |  |  | USER_FILL_HOLES = None | 
					
						
							|  |  |  | USER_FILL_HOLES_QUALITY = None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-03 17:47:44 +00:00
										 |  |  | def pointInTri2D(v, v1, v2, v3): | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |     key = v1.x, v1.y, v2.x, v2.y, v3.x, v3.y | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-17 06:58:07 +00:00
										 |  |  |     # Commented because its slower to do the bounds check, we should really cache the bounds info for each face. | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |     '''
 | 
					
						
							|  |  |  |     # 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) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-09 15:09:18 +00:00
										 |  |  |         mtx = Matrix((side1, side2, nor)) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-08 04:37:37 +00:00
										 |  |  |         # Zero area 2d tri, even tho we throw away zero area faces | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |         # 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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-12 15:01:26 +10:00
										 |  |  |     uvw = (v - v1) @ mtx | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |     return 0 <= uvw[0] and 0 <= uvw[1] and uvw[0] + uvw[1] <= 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-03 17:47:44 +00:00
										 |  |  | def boundsIsland(faces): | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |     minx = maxx = faces[0].uv[0][0]  # Set initial bounds. | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |     miny = maxy = faces[0].uv[0][1] | 
					
						
							|  |  |  |     # print len(faces), minx, maxx, miny , maxy | 
					
						
							|  |  |  |     for f in faces: | 
					
						
							|  |  |  |         for uv in f.uv: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |             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 | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return minx, miny, maxx, maxy | 
					
						
							| 
									
										
										
										
											2009-11-03 17:47:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-03 17:47:44 +00:00
										 |  |  | """
 | 
					
						
							|  |  |  | def boundsEdgeLoop(edges): | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |     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: | 
					
						
							|  |  |  |             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 | 
					
						
							| 
									
										
										
										
											2009-11-03 17:47:44 +00:00
										 |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Turns the islands into a list of unpordered edges (Non internal) | 
					
						
							| 
									
										
										
										
											2011-10-17 06:58:07 +00:00
										 |  |  | # Only for UV's | 
					
						
							| 
									
										
										
										
											2009-11-03 17:47:44 +00:00
										 |  |  | # only returns outline edges for intersection tests. and unique points. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-03 17:47:44 +00:00
										 |  |  | def island2Edge(island): | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Vert index edges | 
					
						
							|  |  |  |     edges = {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |     unique_points = {} | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for f in island: | 
					
						
							| 
									
										
										
										
											2018-10-25 12:24:38 +11:00
										 |  |  |         f_uvkey = list(map(tuple, f.uv)) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-25 12:24:38 +11:00
										 |  |  |         for vIdx in range(len(f_uvkey)): | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |             unique_points[f_uvkey[vIdx]] = f.uv[vIdx] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |             if f.v[vIdx].index > f.v[vIdx - 1].index: | 
					
						
							|  |  |  |                 i1 = vIdx - 1 | 
					
						
							|  |  |  |                 i2 = vIdx | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |             else: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                 i1 = vIdx | 
					
						
							|  |  |  |                 i2 = vIdx - 1 | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |             try: | 
					
						
							|  |  |  |                 edges[f_uvkey[i1], f_uvkey[i2]] *= 0  # sets any edge with more than 1 user to 0 are not returned. | 
					
						
							|  |  |  |             except: | 
					
						
							| 
									
										
										
										
											2018-10-25 12:24:38 +11:00
										 |  |  |                 edges[f_uvkey[i1], f_uvkey[i2]] = (f.uv[i1] - f.uv[i2]).length | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # 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] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-25 12:24:38 +11:00
										 |  |  |     length_sorted_edges.sort(key=lambda a: -a[2])  # largest first | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Its okay to leave the length in there. | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |     # for e in length_sorted_edges: | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |     #	e.pop(2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # return edges and unique points | 
					
						
							| 
									
										
										
										
											2011-02-05 07:04:23 +00:00
										 |  |  |     return length_sorted_edges, [v.to_3d() for v in unique_points.values()] | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-03 17:47:44 +00:00
										 |  |  | def pointInIsland(pt, island): | 
					
						
							| 
									
										
										
										
											2010-04-25 19:27:59 +00:00
										 |  |  |     vec1, vec2, vec3 = Vector(), Vector(), Vector() | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |     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 | 
					
						
							| 
									
										
										
										
											2009-11-03 17:47:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # box is (left,bottom, right, top) | 
					
						
							|  |  |  | def islandIntersectUvIsland(source, target, SourceOffset): | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |     # Is 1 point in the box, inside the vertLoops | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |     edgeLoopsSource = source[6]  # Pretend this is offset | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |     edgeLoopsTarget = target[6] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Edge intersect test | 
					
						
							|  |  |  |     for ed in edgeLoopsSource: | 
					
						
							|  |  |  |         for seg in edgeLoopsTarget: | 
					
						
							| 
									
										
										
										
											2011-11-08 01:32:34 +00:00
										 |  |  |             i = geometry.intersect_line_line_2d(seg[0], | 
					
						
							|  |  |  |                                                 seg[1], | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                                                 SourceOffset + ed[0], | 
					
						
							|  |  |  |                                                 SourceOffset + ed[1], | 
					
						
							| 
									
										
										
										
											2011-11-08 01:32:34 +00:00
										 |  |  |                                                 ) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |             if i: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                 return 1  # LINE INTERSECTION | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # 1 test for source being totally inside target | 
					
						
							| 
									
										
										
										
											2011-02-05 07:04:23 +00:00
										 |  |  |     SourceOffset.resize_3d() | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |     for pv in source[7]: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         if pointInIsland(pv + SourceOffset, target[0]): | 
					
						
							|  |  |  |             return 2  # SOURCE INSIDE TARGET | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-17 06:58:07 +00:00
										 |  |  |     # 2 test for a part of the target being totally inside the source. | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |     for pv in target[7]: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         if pointInIsland(pv - SourceOffset, source[0]): | 
					
						
							|  |  |  |             return 3  # PART OF TARGET INSIDE SOURCE. | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |     return 0  # NO INTERSECTION | 
					
						
							| 
									
										
										
										
											2009-11-03 17:47:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-03 22:03:53 +11:00
										 |  |  | def rotate_uvs(uv_points, angle): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if angle != 0.0: | 
					
						
							|  |  |  |         mat = Matrix.Rotation(angle, 2) | 
					
						
							|  |  |  |         for uv in uv_points: | 
					
						
							| 
									
										
										
										
											2018-08-12 15:01:26 +10:00
										 |  |  |             uv[:] = mat @ uv | 
					
						
							| 
									
										
										
										
											2014-04-03 22:03:53 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-03 17:47:44 +00:00
										 |  |  | def optiRotateUvIsland(faces): | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |     uv_points = [uv for f in faces for uv in f.uv] | 
					
						
							| 
									
										
										
										
											2013-09-11 07:10:15 +00:00
										 |  |  |     angle = geometry.box_fit_2d(uv_points) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if angle != 0.0: | 
					
						
							| 
									
										
										
										
											2014-04-03 22:03:53 +11:00
										 |  |  |         rotate_uvs(uv_points, angle) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # orient them vertically (could be an option) | 
					
						
							|  |  |  |     minx, miny, maxx, maxy = boundsIsland(faces) | 
					
						
							|  |  |  |     w, h = maxx - minx, maxy - miny | 
					
						
							| 
									
										
										
										
											2018-09-03 16:49:08 +02:00
										 |  |  |     # use epsilon so we don't randomly rotate (almost) perfect squares. | 
					
						
							| 
									
										
										
										
											2014-04-25 00:43:15 +10:00
										 |  |  |     if h + 0.00001 < w: | 
					
						
							| 
									
										
										
										
											2014-04-03 22:03:53 +11:00
										 |  |  |         from math import pi | 
					
						
							|  |  |  |         angle = pi / 2.0 | 
					
						
							|  |  |  |         rotate_uvs(uv_points, angle) | 
					
						
							| 
									
										
										
										
											2009-11-03 17:47:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Takes an island list and tries to find concave, hollow areas to pack smaller islands into. | 
					
						
							|  |  |  | def mergeUvIslands(islandList): | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |     global USER_FILL_HOLES | 
					
						
							|  |  |  |     global USER_FILL_HOLES_QUALITY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Pack islands to bottom LHS | 
					
						
							|  |  |  |     # Sync with island | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |     # islandTotFaceArea = [] # A list of floats, each island area | 
					
						
							|  |  |  |     # islandArea = [] # a list of tuples ( area, w,h) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     decoratedIslandList = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     islandIdx = len(islandList) | 
					
						
							|  |  |  |     while islandIdx: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         islandIdx -= 1 | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |         minx, miny, maxx, maxy = boundsIsland(islandList[islandIdx]) | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         w, h = maxx - minx, maxy - miny | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         totFaceArea = 0 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         offset = Vector((minx, miny)) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |         for f in islandList[islandIdx]: | 
					
						
							|  |  |  |             for uv in f.uv: | 
					
						
							|  |  |  |                 uv -= offset | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             totFaceArea += f.area | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         islandBoundsArea = w * h | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |         efficiency = abs(islandBoundsArea - totFaceArea) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # UV Edge list used for intersections as well as unique points. | 
					
						
							|  |  |  |         edges, uniqueEdgePoints = island2Edge(islandList[islandIdx]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         decoratedIslandList.append([islandList[islandIdx], totFaceArea, efficiency, islandBoundsArea, w, h, edges, uniqueEdgePoints]) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Sort by island bounding box area, smallest face area first. | 
					
						
							|  |  |  |     # no.. chance that to most simple edge loop first. | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |     decoratedIslandListAreaSort = decoratedIslandList[:] | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |     decoratedIslandListAreaSort.sort(key=lambda A: A[3]) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # sort by efficiency, Least Efficient first. | 
					
						
							|  |  |  |     decoratedIslandListEfficSort = decoratedIslandList[:] | 
					
						
							|  |  |  |     # decoratedIslandListEfficSort.sort(lambda A, B: cmp(B[2], A[2])) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |     decoratedIslandListEfficSort.sort(key=lambda A: -A[2]) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # ================================================== 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 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |     USER_STEP_QUALITY = ((USER_FILL_HOLES_QUALITY - 1) / 25.0) + 1 | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # 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 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |     USER_FREE_SPACE_TO_TEST_QUALITY = 1 + (((100 - USER_FILL_HOLES_QUALITY) / 100.0) * 5) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |     # print 'USER_STEP_QUALITY', USER_STEP_QUALITY | 
					
						
							|  |  |  |     # print 'USER_FREE_SPACE_TO_TEST_QUALITY', USER_FREE_SPACE_TO_TEST_QUALITY | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     removedCount = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     areaIslandIdx = 0 | 
					
						
							|  |  |  |     ctrl = Window.Qual.CTRL | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |     BREAK = False | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |     while areaIslandIdx < len(decoratedIslandListAreaSort) and not BREAK: | 
					
						
							|  |  |  |         sourceIsland = decoratedIslandListAreaSort[areaIslandIdx] | 
					
						
							| 
									
										
										
										
											2011-10-17 06:58:07 +00:00
										 |  |  |         # Already packed? | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |         if not sourceIsland[0]: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |             areaIslandIdx += 1 | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |         else: | 
					
						
							|  |  |  |             efficIslandIdx = 0 | 
					
						
							|  |  |  |             while efficIslandIdx < len(decoratedIslandListEfficSort) and not BREAK: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if Window.GetKeyQualifiers() & ctrl: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                     BREAK = True | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |                     break | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-03 16:49:08 +02:00
										 |  |  |                 # Now we have 2 islands, if the efficiency of the islands lowers there's an | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |                 # 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\ | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                         not targetIsland[0] or\ | 
					
						
							|  |  |  |                         not sourceIsland[0]: | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |                     pass | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-17 06:58:07 +00:00
										 |  |  |                     #~ ([island, totFaceArea, efficiency, islandArea, w,h]) | 
					
						
							|  |  |  |                     # Wasted space on target is greater then UV bounding island area. | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-17 06:58:07 +00:00
										 |  |  |                     #~ if targetIsland[3] > (sourceIsland[2]) and\ # | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                     # ~ print USER_FREE_SPACE_TO_TEST_QUALITY | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |                     if targetIsland[2] > (sourceIsland[1] * USER_FREE_SPACE_TO_TEST_QUALITY) and\ | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                             targetIsland[4] > sourceIsland[4] and\ | 
					
						
							|  |  |  |                             targetIsland[5] > sourceIsland[5]: | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                         # 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 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                         blockTestXUnit = targetIsland[4] / sourceIsland[4] | 
					
						
							|  |  |  |                         blockTestYUnit = targetIsland[5] / sourceIsland[5] | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                         boxLeft = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-17 06:58:07 +00:00
										 |  |  |                         # Distance we can move between whilst staying inside the targets bounds. | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |                         testWidth = targetIsland[4] - sourceIsland[4] | 
					
						
							|  |  |  |                         testHeight = targetIsland[5] - sourceIsland[5] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         # Increment we move each test. x/y | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                         xIncrement = (testWidth / (blockTestXUnit * ((USER_STEP_QUALITY / 50) + 0.1))) | 
					
						
							|  |  |  |                         yIncrement = (testHeight / (blockTestYUnit * ((USER_STEP_QUALITY / 50) + 0.1))) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                         # Make sure were not moving less then a 3rg of our width/height | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                         if xIncrement < sourceIsland[4] / 3: | 
					
						
							|  |  |  |                             xIncrement = sourceIsland[4] | 
					
						
							|  |  |  |                         if yIncrement < sourceIsland[5] / 3: | 
					
						
							|  |  |  |                             yIncrement = sourceIsland[5] | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                         boxLeft = 0  # Start 1 back so we can jump into the loop. | 
					
						
							|  |  |  |                         boxBottom = 0  # -yIncrement | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                         # ~ testcount= 0 | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                         while boxBottom <= testHeight: | 
					
						
							|  |  |  |                             # Should we use this? - not needed for now. | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                             # ~ if Window.GetKeyQualifiers() & ctrl: | 
					
						
							|  |  |  |                             # ~     BREAK= True | 
					
						
							|  |  |  |                             # ~     break | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                             # testcount+=1 | 
					
						
							|  |  |  |                             # print 'Testing intersect' | 
					
						
							| 
									
										
										
										
											2010-04-25 19:27:59 +00:00
										 |  |  |                             Intersect = islandIntersectUvIsland(sourceIsland, targetIsland, Vector((boxLeft, boxBottom))) | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                             # print 'Done', Intersect | 
					
						
							| 
									
										
										
										
											2011-10-17 06:58:07 +00:00
										 |  |  |                             if Intersect == 1:  # Line intersect, don't bother with this any more | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |                                 pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                             if Intersect == 2:  # Source inside target | 
					
						
							| 
									
										
										
										
											2012-07-03 09:02:41 +00:00
										 |  |  |                                 """
 | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |                                 We have an intersection, if we are inside the target | 
					
						
							| 
									
										
										
										
											2011-10-17 06:58:07 +00:00
										 |  |  |                                 then move us 1 whole width across, | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |                                 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 | 
					
						
							| 
									
										
										
										
											2010-07-17 18:08:14 +00:00
										 |  |  |                                 since we have already tested for it. | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                                 It gives about 10% speedup with minimal errors. | 
					
						
							| 
									
										
										
										
											2012-07-03 09:02:41 +00:00
										 |  |  |                                 """
 | 
					
						
							| 
									
										
										
										
											2011-10-17 06:58:07 +00:00
										 |  |  |                                 # Move the test along its width + SMALL_NUM | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |                                 #boxLeft += sourceIsland[4] + SMALL_NUM | 
					
						
							|  |  |  |                                 boxLeft += sourceIsland[4] | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                             elif Intersect == 0:  # No intersection?? Place it. | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |                                 # Progress | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                                 removedCount += 1 | 
					
						
							|  |  |  | # XXX								Window.DrawProgressBar(0.0, 'Merged: %i islands, Ctrl to finish early.' % removedCount) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                                 # Move faces into new island and offset | 
					
						
							|  |  |  |                                 targetIsland[0].extend(sourceIsland[0]) | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                                 offset = Vector((boxLeft, boxBottom)) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                                 for f in sourceIsland[0]: | 
					
						
							|  |  |  |                                     for uv in f.uv: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                                         uv += offset | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-14 09:45:15 +00:00
										 |  |  |                                 del sourceIsland[0][:]  # Empty | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                                 # Move edge loop into new and offset. | 
					
						
							|  |  |  |                                 # targetIsland[6].extend(sourceIsland[6]) | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                                 # while sourceIsland[6]: | 
					
						
							|  |  |  |                                 targetIsland[6].extend([( | 
					
						
							|  |  |  |                                     (e[0] + offset, e[1] + offset, e[2]) | 
					
						
							|  |  |  |                                 ) for e in sourceIsland[6]]) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-14 09:45:15 +00:00
										 |  |  |                                 del sourceIsland[6][:]  # Empty | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                                 # Sort by edge length, reverse so biggest are first. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                                 try: | 
					
						
							|  |  |  |                                     targetIsland[6].sort(key=lambda A: A[2]) | 
					
						
							|  |  |  |                                 except: | 
					
						
							|  |  |  |                                     targetIsland[6].sort(lambda B, A: cmp(A[2], B[2])) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                                 targetIsland[7].extend(sourceIsland[7]) | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                                 offset = Vector((boxLeft, boxBottom, 0.0)) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |                                 for p in sourceIsland[7]: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                                     p += offset | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-14 09:45:15 +00:00
										 |  |  |                                 del sourceIsland[7][:] | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                                 # Decrement the efficiency | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                                 targetIsland[1] += sourceIsland[1]  # Increment totFaceArea | 
					
						
							|  |  |  |                                 targetIsland[2] -= sourceIsland[1]  # Decrement efficiency | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |                                 # IF we ever used these again, should set to 0, eg | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                                 sourceIsland[2] = 0  # No area if anyone wants to know | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                                 break | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-17 06:58:07 +00:00
										 |  |  |                             # INCREMENT NEXT LOCATION | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |                             if boxLeft > testWidth: | 
					
						
							|  |  |  |                                 boxBottom += yIncrement | 
					
						
							|  |  |  |                                 boxLeft = 0.0 | 
					
						
							|  |  |  |                             else: | 
					
						
							|  |  |  |                                 boxLeft += xIncrement | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                         # print testcount | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                 efficIslandIdx += 1 | 
					
						
							|  |  |  |         areaIslandIdx += 1 | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Remove empty islands | 
					
						
							|  |  |  |     i = len(islandList) | 
					
						
							|  |  |  |     while i: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         i -= 1 | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |         if not islandList[i]: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |             del islandList[i]  # Can increment islands removed here. | 
					
						
							| 
									
										
										
										
											2009-11-03 17:47:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # Takes groups of faces. assumes face groups are UV groups. | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-03 17:47:44 +00:00
										 |  |  | def getUvIslands(faceGroups, me): | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-17 06:58:07 +00:00
										 |  |  |     # Get seams so we don't cross over seams | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |     edge_seams = {}  # should be a set | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |     for ed in me.edges: | 
					
						
							| 
									
										
										
										
											2010-08-18 07:14:10 +00:00
										 |  |  |         if ed.use_seam: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |             edge_seams[ed.key] = None  # dummy var- use sets! | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |     # Done finding seams | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     islandList = [] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  | # XXX	Window.DrawProgressBar(0.0, 'Splitting %d projection groups into UV islands:' % len(faceGroups)) | 
					
						
							|  |  |  |     # print '\tSplitting %d projection groups into UV islands:' % len(faceGroups), | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |     # Find grouped faces | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     faceGroupIdx = len(faceGroups) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while faceGroupIdx: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         faceGroupIdx -= 1 | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |         faces = faceGroups[faceGroupIdx] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if not faces: | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Build edge dict | 
					
						
							|  |  |  |         edge_users = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for i, f in enumerate(faces): | 
					
						
							|  |  |  |             for ed_key in f.edge_keys: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                 if ed_key in edge_seams:  # DELIMIT SEAMS! ;) | 
					
						
							|  |  |  |                     edge_users[ed_key] = []  # so as not to raise an error | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |                 else: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                     try: | 
					
						
							|  |  |  |                         edge_users[ed_key].append(i) | 
					
						
							|  |  |  |                     except: | 
					
						
							|  |  |  |                         edge_users[ed_key] = [i] | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # Modes | 
					
						
							|  |  |  |         # 0 - face not yet touched. | 
					
						
							|  |  |  |         # 1 - added to island list, and need to search | 
					
						
							| 
									
										
										
										
											2011-10-17 06:58:07 +00:00
										 |  |  |         # 2 - touched and searched - don't touch again. | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         face_modes = [0] * len(faces)  # initialize zero - untested. | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         face_modes[0] = 1  # start the search with face 1 | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         newIsland = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         newIsland.append(faces[0]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ok = True | 
					
						
							|  |  |  |         while ok: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             ok = True | 
					
						
							|  |  |  |             while ok: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                 ok = False | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |                 for i in range(len(faces)): | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                     if face_modes[i] == 1:  # search | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |                         for ed_key in faces[i].edge_keys: | 
					
						
							|  |  |  |                             for ii in edge_users[ed_key]: | 
					
						
							|  |  |  |                                 if i != ii and face_modes[ii] == 0: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                                     face_modes[ii] = ok = 1  # mark as searched | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |                                     newIsland.append(faces[ii]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-17 06:58:07 +00:00
										 |  |  |                         # mark as searched, don't look again. | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |                         face_modes[i] = 2 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             islandList.append(newIsland) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             ok = False | 
					
						
							|  |  |  |             for i in range(len(faces)): | 
					
						
							|  |  |  |                 if face_modes[i] == 0: | 
					
						
							|  |  |  |                     newIsland = [] | 
					
						
							|  |  |  |                     newIsland.append(faces[i]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     face_modes[i] = ok = 1 | 
					
						
							|  |  |  |                     break | 
					
						
							|  |  |  |             # if not ok will stop looping | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  | # XXX	Window.DrawProgressBar(0.1, 'Optimizing Rotation for %i UV Islands' % len(islandList)) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for island in islandList: | 
					
						
							|  |  |  |         optiRotateUvIsland(island) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return islandList | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-03 17:47:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def packIslands(islandList): | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |     if USER_FILL_HOLES: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         # XXX		Window.DrawProgressBar(0.1, 'Merging Islands (Ctrl: skip merge)...') | 
					
						
							|  |  |  |         mergeUvIslands(islandList)  # Modify in place | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Now we have UV islands, we need to pack them. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-17 06:58:07 +00:00
										 |  |  |     # Make a synchronized list with the islands | 
					
						
							|  |  |  |     # so we can box pack the islands. | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |     packBoxes = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Keep a list of X/Y offset so we can save time by writing the | 
					
						
							|  |  |  |     # uv's and packed data in one pass. | 
					
						
							|  |  |  |     islandOffsetList = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     islandIdx = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while islandIdx < len(islandList): | 
					
						
							|  |  |  |         minx, miny, maxx, maxy = boundsIsland(islandList[islandIdx]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         w, h = maxx - minx, maxy - miny | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if USER_ISLAND_MARGIN: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |             minx -= USER_ISLAND_MARGIN  # *w | 
					
						
							|  |  |  |             miny -= USER_ISLAND_MARGIN  # *h | 
					
						
							|  |  |  |             maxx += USER_ISLAND_MARGIN  # *w | 
					
						
							|  |  |  |             maxy += USER_ISLAND_MARGIN  # *h | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             # recalc width and height | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |             w, h = maxx - minx, maxy - miny | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-18 01:34:14 +11:00
										 |  |  |         if w < SMALL_NUM: | 
					
						
							|  |  |  |             w = SMALL_NUM | 
					
						
							|  |  |  |         if h < SMALL_NUM: | 
					
						
							|  |  |  |             h = SMALL_NUM | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-03 09:02:41 +00:00
										 |  |  |         """Save the offset to be applied later,
 | 
					
						
							| 
									
										
										
										
											2018-09-03 16:49:08 +02:00
										 |  |  |         we could apply to the UVs now and align them to the bottom left hand area | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |         of the UV coords like the box packer imagines they are | 
					
						
							|  |  |  |         but, its quicker just to remember their offset and | 
					
						
							| 
									
										
										
										
											2012-07-03 09:02:41 +00:00
										 |  |  |         apply the packing and offset in 1 pass """
 | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |         islandOffsetList.append((minx, miny)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Add to boxList. use the island idx for the BOX id. | 
					
						
							|  |  |  |         packBoxes.append([0, 0, w, h]) | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         islandIdx += 1 | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Now we have a list of boxes to pack that syncs | 
					
						
							|  |  |  |     # with the islands. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |     # print '\tPacking UV Islands...' | 
					
						
							|  |  |  | # XXX	Window.DrawProgressBar(0.7, "Packing %i UV Islands..." % len(packBoxes) ) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-27 14:16:32 +00:00
										 |  |  |     # time1 = time.time() | 
					
						
							| 
									
										
										
										
											2011-01-02 02:11:38 +00:00
										 |  |  |     packWidth, packHeight = geometry.box_pack_2d(packBoxes) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # print 'Box Packing Time:', time.time() - time1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |     # if len(pa	ckedLs) != len(islandList): | 
					
						
							| 
									
										
										
										
											2014-08-07 00:42:49 +10:00
										 |  |  |     #    raise ValueError("Packed boxes differs from original length") | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |     # print '\tWriting Packed Data to faces' | 
					
						
							|  |  |  | # XXX	Window.DrawProgressBar(0.8, "Writing Packed Data to faces") | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Sort by ID, so there in sync again | 
					
						
							|  |  |  |     islandIdx = len(islandList) | 
					
						
							| 
									
										
										
										
											2011-10-17 06:58:07 +00:00
										 |  |  |     # Having these here avoids divide by 0 | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |     if islandIdx: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if USER_STRETCH_ASPECT: | 
					
						
							|  |  |  |             # Maximize to uv area?? Will write a normalize function. | 
					
						
							|  |  |  |             xfactor = 1.0 / packWidth | 
					
						
							|  |  |  |             yfactor = 1.0 / packHeight | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             # Keep proportions. | 
					
						
							|  |  |  |             xfactor = yfactor = 1.0 / max(packWidth, packHeight) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while islandIdx: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         islandIdx -= 1 | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |         # Write the packed values to the UV's | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         xoffset = packBoxes[islandIdx][0] - islandOffsetList[islandIdx][0] | 
					
						
							|  |  |  |         yoffset = packBoxes[islandIdx][1] - islandOffsetList[islandIdx][1] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         for f in islandList[islandIdx]:  # Offsetting the UV's so they fit in there packed box | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |             for uv in f.uv: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                 uv.x = (uv.x + xoffset) * xfactor | 
					
						
							|  |  |  |                 uv.y = (uv.y + yoffset) * yfactor | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-23 16:10:20 +00:00
										 |  |  | def VectoQuat(vec): | 
					
						
							| 
									
										
										
										
											2011-07-18 06:44:41 +00:00
										 |  |  |     vec = vec.normalized() | 
					
						
							|  |  |  |     return vec.to_track_quat('Z', 'X' if abs(vec.x) > 0.5 else 'Y').inverted() | 
					
						
							| 
									
										
										
										
											2009-11-03 17:47:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-28 18:42:06 +01:00
										 |  |  | class thickface: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |     __slost__ = "v", "uv", "no", "area", "edge_keys" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-17 05:03:07 +00:00
										 |  |  |     def __init__(self, face, uv_layer, mesh_verts): | 
					
						
							| 
									
										
										
										
											2010-08-18 03:42:26 +00:00
										 |  |  |         self.v = [mesh_verts[i] for i in face.vertices] | 
					
						
							| 
									
										
										
										
											2012-04-13 08:41:30 +00:00
										 |  |  |         self.uv = [uv_layer[i].uv for i in face.loop_indices] | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-26 11:53:34 +00:00
										 |  |  |         self.no = face.normal.copy() | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |         self.area = face.area | 
					
						
							|  |  |  |         self.edge_keys = face.edge_keys | 
					
						
							| 
									
										
										
										
											2009-11-03 17:47:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-27 14:16:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def main_consts(): | 
					
						
							|  |  |  |     from math import radians | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     global ROTMAT_2D_POS_90D | 
					
						
							|  |  |  |     global ROTMAT_2D_POS_45D | 
					
						
							|  |  |  |     global RotMatStepRotation | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-08 01:32:34 +00:00
										 |  |  |     ROTMAT_2D_POS_90D = Matrix.Rotation(radians(90.0), 2) | 
					
						
							|  |  |  |     ROTMAT_2D_POS_45D = Matrix.Rotation(radians(45.0), 2) | 
					
						
							| 
									
										
										
										
											2011-02-27 14:16:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     RotMatStepRotation = [] | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |     rot_angle = 22.5  # 45.0/2 | 
					
						
							| 
									
										
										
										
											2011-02-27 14:16:32 +00:00
										 |  |  |     while rot_angle > 0.1: | 
					
						
							| 
									
										
										
										
											2011-11-08 01:32:34 +00:00
										 |  |  |         RotMatStepRotation.append([ | 
					
						
							|  |  |  |             Matrix.Rotation(radians(+rot_angle), 2), | 
					
						
							|  |  |  |             Matrix.Rotation(radians(-rot_angle), 2), | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         ]) | 
					
						
							| 
									
										
										
										
											2011-02-27 14:16:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         rot_angle = rot_angle / 2.0 | 
					
						
							| 
									
										
										
										
											2011-02-27 14:16:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-03 17:47:44 +00:00
										 |  |  | global ob | 
					
						
							|  |  |  | ob = None | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-28 06:51:55 +00:00
										 |  |  | def main(context, | 
					
						
							|  |  |  |          island_margin, | 
					
						
							|  |  |  |          projection_limit, | 
					
						
							|  |  |  |          user_area_weight, | 
					
						
							| 
									
										
										
										
											2015-11-24 07:28:42 +11:00
										 |  |  |          use_aspect, | 
					
						
							|  |  |  |          stretch_to_bounds, | 
					
						
							| 
									
										
										
										
											2011-06-28 06:51:55 +00:00
										 |  |  |          ): | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |     global USER_FILL_HOLES | 
					
						
							|  |  |  |     global USER_FILL_HOLES_QUALITY | 
					
						
							|  |  |  |     global USER_STRETCH_ASPECT | 
					
						
							|  |  |  |     global USER_ISLAND_MARGIN | 
					
						
							| 
									
										
										
										
											2017-07-25 01:27:43 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-27 14:16:32 +00:00
										 |  |  |     from math import cos | 
					
						
							|  |  |  |     import time | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     global dict_matrix | 
					
						
							|  |  |  |     dict_matrix = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Constants: | 
					
						
							|  |  |  |     # Takes a list of faces that make up a UV island and rotate | 
					
						
							|  |  |  |     # until they optimally fit inside a square. | 
					
						
							|  |  |  |     global ROTMAT_2D_POS_90D | 
					
						
							|  |  |  |     global ROTMAT_2D_POS_45D | 
					
						
							|  |  |  |     global RotMatStepRotation | 
					
						
							|  |  |  |     main_consts() | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-15 16:25:05 +00:00
										 |  |  |     # Create the variables. | 
					
						
							|  |  |  |     USER_PROJECTION_LIMIT = projection_limit | 
					
						
							|  |  |  |     USER_ONLY_SELECTED_FACES = True | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |     USER_SHARE_SPACE = 1  # Only for hole filling. | 
					
						
							| 
									
										
										
										
											2015-11-24 07:28:42 +11:00
										 |  |  |     USER_STRETCH_ASPECT = stretch_to_bounds | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |     USER_ISLAND_MARGIN = island_margin  # Only for hole filling. | 
					
						
							| 
									
										
										
										
											2011-08-15 16:25:05 +00:00
										 |  |  |     USER_FILL_HOLES = 0 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |     USER_FILL_HOLES_QUALITY = 50  # Only for hole filling. | 
					
						
							|  |  |  |     USER_VIEW_INIT = 0  # Only for hole filling. | 
					
						
							| 
									
										
										
										
											2017-07-25 01:27:43 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-05 15:23:39 -03:00
										 |  |  |     obList = [ob for ob in context.selected_editable_objects if ob and ob.type == 'MESH'] | 
					
						
							| 
									
										
										
										
											2018-04-05 18:20:27 +02:00
										 |  |  |     is_editmode = (context.active_object.mode == 'EDIT') | 
					
						
							| 
									
										
										
										
											2018-09-05 15:23:39 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if not is_editmode: | 
					
						
							| 
									
										
										
										
											2011-08-15 16:25:05 +00:00
										 |  |  |         USER_ONLY_SELECTED_FACES = False | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if not obList: | 
					
						
							| 
									
										
										
										
											2012-06-19 22:17:19 +00:00
										 |  |  |         raise Exception("error, no selected mesh objects") | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Reuse variable | 
					
						
							|  |  |  |     if len(obList) == 1: | 
					
						
							|  |  |  |         ob = "Unwrap %i Selected Mesh" | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         ob = "Unwrap %i Selected Meshes" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Convert from being button types | 
					
						
							|  |  |  |     USER_PROJECTION_LIMIT_CONVERTED = cos(USER_PROJECTION_LIMIT * DEG_TO_RAD) | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |     USER_PROJECTION_LIMIT_HALF_CONVERTED = cos((USER_PROJECTION_LIMIT / 2) * DEG_TO_RAD) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Toggle Edit mode | 
					
						
							|  |  |  |     if is_editmode: | 
					
						
							|  |  |  |         bpy.ops.object.mode_set(mode='OBJECT') | 
					
						
							| 
									
										
										
										
											2011-10-17 06:58:07 +00:00
										 |  |  |     # Assume face select mode! an annoying hack to toggle face select mode because Mesh doesn't like faceSelectMode. | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if USER_SHARE_SPACE: | 
					
						
							| 
									
										
										
										
											2011-10-17 06:58:07 +00:00
										 |  |  |         # Sort by data name so we get consistent results | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         obList.sort(key=lambda ob: ob.data.name) | 
					
						
							|  |  |  |         collected_islandList = [] | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     time1 = time.time() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-17 06:58:07 +00:00
										 |  |  |     # Tag as False so we don't operate on the same mesh twice. | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |     for me in bpy.data.meshes: | 
					
						
							|  |  |  |         me.tag = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for ob in obList: | 
					
						
							|  |  |  |         me = ob.data | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if me.tag or me.library: | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Tag as used | 
					
						
							|  |  |  |         me.tag = True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 22:56:39 +02:00
										 |  |  |         if not me.uv_layers:  # Mesh has no UV Coords, don't bother. | 
					
						
							| 
									
										
										
										
											2017-05-25 15:11:00 +10:00
										 |  |  |             me.uv_layers.new() | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-22 23:51:50 +00:00
										 |  |  |         uv_layer = me.uv_layers.active.data | 
					
						
							| 
									
										
										
										
											2010-08-18 03:42:26 +00:00
										 |  |  |         me_verts = list(me.vertices) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if USER_ONLY_SELECTED_FACES: | 
					
						
							| 
									
										
										
										
											2011-11-17 05:03:07 +00:00
										 |  |  |             meshFaces = [thickface(f, uv_layer, me_verts) for i, f in enumerate(me.polygons) if f.select] | 
					
						
							| 
									
										
										
										
											2011-08-15 16:25:05 +00:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2011-11-17 05:03:07 +00:00
										 |  |  |             meshFaces = [thickface(f, uv_layer, me_verts) for i, f in enumerate(me.polygons)] | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # ======= | 
					
						
							| 
									
										
										
										
											2011-10-17 06:58:07 +00:00
										 |  |  |         # Generate a projection list from face normals, this is meant to be smart :) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # make a list of face props that are in sync with meshFaces | 
					
						
							|  |  |  |         # Make a Face List that is sorted by area. | 
					
						
							|  |  |  |         # meshFaces = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # meshFaces.sort( lambda a, b: cmp(b.area , a.area) ) # Biggest first. | 
					
						
							| 
									
										
										
										
											2011-08-15 16:25:05 +00:00
										 |  |  |         meshFaces.sort(key=lambda a: -a.area) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # remove all zero area faces | 
					
						
							|  |  |  |         while meshFaces and meshFaces[-1].area <= SMALL_NUM: | 
					
						
							|  |  |  |             # Set their UV's to 0,0 | 
					
						
							|  |  |  |             for uv in meshFaces[-1].uv: | 
					
						
							|  |  |  |                 uv.zero() | 
					
						
							|  |  |  |             meshFaces.pop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-20 11:49:14 +10:00
										 |  |  |         if not meshFaces: | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-30 09:03:37 +11:00
										 |  |  |         # Smallest first is slightly more efficient, | 
					
						
							|  |  |  |         # but if the user cancels early then its better we work on the larger data. | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # Generate Projection Vecs | 
					
						
							|  |  |  |         # 0d is   1.0 | 
					
						
							|  |  |  |         # 180 IS -0.59846 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Initialize projectVecs | 
					
						
							|  |  |  |         if USER_VIEW_INIT: | 
					
						
							|  |  |  |             # Generate Projection | 
					
						
							| 
									
										
										
										
											2019-01-30 09:03:37 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  |             # We add to this along the way | 
					
						
							|  |  |  |             projectVecs = [Vector(Window.GetViewVector()) @ ob.matrix_world.inverted().to_3x3()] | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |         else: | 
					
						
							|  |  |  |             projectVecs = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         newProjectVec = meshFaces[0].no | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         newProjectMeshFaces = []  # Popping stuffs it up. | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-17 06:58:07 +00:00
										 |  |  |         # Pretend that the most unique angle is ages away to start the loop off | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |         mostUniqueAngle = -1.0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # This is popped | 
					
						
							|  |  |  |         tempMeshFaces = meshFaces[:] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # This while only gathers projection vecs, faces are assigned later on. | 
					
						
							|  |  |  |         while 1: | 
					
						
							| 
									
										
										
										
											2018-09-03 16:49:08 +02:00
										 |  |  |             # If there's none there then start with the largest face | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             # add all the faces that are close. | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |             for fIdx in range(len(tempMeshFaces) - 1, -1, -1): | 
					
						
							| 
									
										
										
										
											2011-10-17 06:58:07 +00:00
										 |  |  |                 # Use half the angle limit so we don't overweight faces towards this | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |                 # normal and hog all the faces. | 
					
						
							|  |  |  |                 if newProjectVec.dot(tempMeshFaces[fIdx].no) > USER_PROJECTION_LIMIT_HALF_CONVERTED: | 
					
						
							|  |  |  |                     newProjectMeshFaces.append(tempMeshFaces.pop(fIdx)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Add the average of all these faces normals as a projectionVec | 
					
						
							| 
									
										
										
										
											2010-04-29 18:40:33 +00:00
										 |  |  |             averageVec = Vector((0.0, 0.0, 0.0)) | 
					
						
							| 
									
										
										
										
											2011-06-28 06:51:55 +00:00
										 |  |  |             if user_area_weight == 0.0: | 
					
						
							|  |  |  |                 for fprop in newProjectMeshFaces: | 
					
						
							|  |  |  |                     averageVec += fprop.no | 
					
						
							|  |  |  |             elif user_area_weight == 1.0: | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |                 for fprop in newProjectMeshFaces: | 
					
						
							| 
									
										
										
										
											2011-06-28 06:51:55 +00:00
										 |  |  |                     averageVec += fprop.no * fprop.area | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |             else: | 
					
						
							|  |  |  |                 for fprop in newProjectMeshFaces: | 
					
						
							| 
									
										
										
										
											2011-06-28 06:51:55 +00:00
										 |  |  |                     averageVec += fprop.no * ((fprop.area * user_area_weight) + (1.0 - user_area_weight)) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |             if averageVec.x != 0 or averageVec.y != 0 or averageVec.z != 0:  # Avoid NAN | 
					
						
							| 
									
										
										
										
											2011-02-06 06:59:11 +00:00
										 |  |  |                 projectVecs.append(averageVec.normalized()) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             # Get the next vec! | 
					
						
							| 
									
										
										
										
											2018-09-19 17:48:11 +02:00
										 |  |  |             # Pick the face that's most different to all existing angles :) | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |             mostUniqueAngle = 1.0  # 1.0 is 0d. no difference. | 
					
						
							|  |  |  |             mostUniqueIndex = 0  # dummy | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |             for fIdx in range(len(tempMeshFaces) - 1, -1, -1): | 
					
						
							|  |  |  |                 angleDifference = -1.0  # 180d difference. | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 # Get the closest vec angle we are to. | 
					
						
							|  |  |  |                 for p in projectVecs: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                     temp_angle_diff = p.dot(tempMeshFaces[fIdx].no) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                     if angleDifference < temp_angle_diff: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                         angleDifference = temp_angle_diff | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 if angleDifference < mostUniqueAngle: | 
					
						
							|  |  |  |                     # We have a new most different angle | 
					
						
							|  |  |  |                     mostUniqueIndex = fIdx | 
					
						
							|  |  |  |                     mostUniqueAngle = angleDifference | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if mostUniqueAngle < USER_PROJECTION_LIMIT_CONVERTED: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                 # print 'adding', mostUniqueAngle, USER_PROJECTION_LIMIT, len(newProjectMeshFaces) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |                 # Now weight the vector to all its faces, will give a more direct projection | 
					
						
							| 
									
										
										
										
											2012-11-28 06:43:04 +00:00
										 |  |  |                 # if the face its self was not representative of the normal from surrounding faces. | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 newProjectVec = tempMeshFaces[mostUniqueIndex].no | 
					
						
							|  |  |  |                 newProjectMeshFaces = [tempMeshFaces.pop(mostUniqueIndex)] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             else: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                 if len(projectVecs) >= 1:  # Must have at least 2 projections | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |                     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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         faceProjectionGroupList = [[] for i in range(len(projectVecs))] | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # MAP and Arrange # We know there are 3 or 4 faces here | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         for fIdx in range(len(meshFaces) - 1, -1, -1): | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |             fvec = meshFaces[fIdx].no | 
					
						
							|  |  |  |             i = len(projectVecs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Initialize first | 
					
						
							|  |  |  |             bestAng = fvec.dot(projectVecs[0]) | 
					
						
							|  |  |  |             bestAngIdx = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-17 18:08:14 +00:00
										 |  |  |             # Cycle through the remaining, first already done | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |             while i - 1: | 
					
						
							|  |  |  |                 i -= 1 | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 newAng = fvec.dot(projectVecs[i]) | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |                 if newAng > bestAng:  # Reverse logic for dotvecs | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |                     bestAng = newAng | 
					
						
							|  |  |  |                     bestAngIdx = i | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Store the area for later use. | 
					
						
							|  |  |  |             faceProjectionGroupList[bestAngIdx].append(meshFaces[fIdx]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # 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. | 
					
						
							|  |  |  |             if not faceProjectionGroupList[i]: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Make a projection matrix from a unit length vector. | 
					
						
							| 
									
										
										
										
											2010-11-23 16:10:20 +00:00
										 |  |  |             MatQuat = VectoQuat(projectVecs[i]) | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             # Get the faces UV's from the projected vertex. | 
					
						
							|  |  |  |             for f in faceProjectionGroupList[i]: | 
					
						
							|  |  |  |                 f_uv = f.uv | 
					
						
							|  |  |  |                 for j, v in enumerate(f.v): | 
					
						
							| 
									
										
										
										
											2018-08-12 15:01:26 +10:00
										 |  |  |                     f_uv[j][:] = (MatQuat @ v.co).xy | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if USER_SHARE_SPACE: | 
					
						
							|  |  |  |             # Should we collect and pack later? | 
					
						
							|  |  |  |             islandList = getUvIslands(faceProjectionGroupList, me) | 
					
						
							|  |  |  |             collected_islandList.extend(islandList) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             # Should we pack the islands for this 1 object? | 
					
						
							|  |  |  |             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: | 
					
						
							|  |  |  |         packIslands(collected_islandList) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     print("Smart Projection time: %.2f" % (time.time() - time1)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-11 19:46:35 +01:00
										 |  |  |     # aspect correction is only done in edit mode - and only smart unwrap supports currently | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |     if is_editmode: | 
					
						
							|  |  |  |         bpy.ops.object.mode_set(mode='EDIT') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-11 19:46:35 +01:00
										 |  |  |         if use_aspect: | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |             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 | 
					
						
							| 
									
										
										
										
											2014-12-11 19:46:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |             bm = bmesh.from_edit_mesh(me) | 
					
						
							| 
									
										
										
										
											2014-12-11 19:46:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |             uv_act = bm.loops.layers.uv.active | 
					
						
							| 
									
										
										
										
											2014-12-11 19:46:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |             faces = [f for f in bm.faces if f.select] | 
					
						
							| 
									
										
										
										
											2014-12-11 19:46:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |             for f in faces: | 
					
						
							|  |  |  |                 for l in f.loops: | 
					
						
							|  |  |  |                     l[uv_act].uv[0] *= aspect[0] | 
					
						
							|  |  |  |                     l[uv_act].uv[1] *= aspect[1] | 
					
						
							| 
									
										
										
										
											2014-12-11 19:46:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-27 14:16:32 +00:00
										 |  |  |     dict_matrix.clear() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-03 18:56:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-11 19:46:35 +01:00
										 |  |  | from bpy.props import FloatProperty, BoolProperty | 
					
						
							| 
									
										
										
										
											2009-12-26 09:36:50 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-12 06:57:00 +00:00
										 |  |  | class SmartProject(Operator): | 
					
						
							| 
									
										
										
										
											2012-07-03 09:02:41 +00:00
										 |  |  |     """This script projection unwraps the selected faces of a mesh """ \ | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         """(it operates on all selected mesh objects, and can be used """ \ | 
					
						
							|  |  |  |         """to unwrap selected faces, or all faces)""" | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |     bl_idname = "uv.smart_project" | 
					
						
							|  |  |  |     bl_label = "Smart UV Project" | 
					
						
							| 
									
										
										
										
											2010-03-01 00:03:51 +00:00
										 |  |  |     bl_options = {'REGISTER', 'UNDO'} | 
					
						
							| 
									
										
										
										
											2009-11-03 18:56:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-11 22:18:09 +02:00
										 |  |  |     angle_limit: FloatProperty( | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         name="Angle Limit", | 
					
						
							|  |  |  |         description="Lower for more projection groups, higher for less distortion", | 
					
						
							|  |  |  |         min=1.0, max=89.0, | 
					
						
							|  |  |  |         default=66.0, | 
					
						
							|  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2018-07-11 22:18:09 +02:00
										 |  |  |     island_margin: FloatProperty( | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         name="Island Margin", | 
					
						
							|  |  |  |         description="Margin to reduce bleed from adjacent islands", | 
					
						
							|  |  |  |         min=0.0, max=1.0, | 
					
						
							|  |  |  |         default=0.0, | 
					
						
							|  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2018-07-11 22:18:09 +02:00
										 |  |  |     user_area_weight: FloatProperty( | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         name="Area Weight", | 
					
						
							|  |  |  |         description="Weight projections vector by faces with larger areas", | 
					
						
							|  |  |  |         min=0.0, max=1.0, | 
					
						
							|  |  |  |         default=0.0, | 
					
						
							|  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2018-07-11 22:18:09 +02:00
										 |  |  |     use_aspect: BoolProperty( | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         name="Correct Aspect", | 
					
						
							|  |  |  |         description="Map UVs taking image aspect ratio into account", | 
					
						
							|  |  |  |         default=True | 
					
						
							|  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2018-07-11 22:18:09 +02:00
										 |  |  |     stretch_to_bounds: BoolProperty( | 
					
						
							| 
									
										
										
										
											2018-06-26 19:41:37 +02:00
										 |  |  |         name="Stretch to UV Bounds", | 
					
						
							|  |  |  |         description="Stretch the final output to texture bounds", | 
					
						
							|  |  |  |         default=True, | 
					
						
							|  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2009-11-03 18:56:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-09 01:37:09 +00:00
										 |  |  |     @classmethod | 
					
						
							|  |  |  |     def poll(cls, context): | 
					
						
							| 
									
										
										
										
											2011-08-22 09:01:49 +00:00
										 |  |  |         return context.active_object is not None | 
					
						
							| 
									
										
										
										
											2009-11-03 17:51:22 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-28 23:37:56 +00:00
										 |  |  |     def execute(self, context): | 
					
						
							| 
									
										
										
										
											2011-06-28 06:51:55 +00:00
										 |  |  |         main(context, | 
					
						
							|  |  |  |              self.island_margin, | 
					
						
							|  |  |  |              self.angle_limit, | 
					
						
							|  |  |  |              self.user_area_weight, | 
					
						
							| 
									
										
										
										
											2015-11-24 07:28:42 +11:00
										 |  |  |              self.use_aspect, | 
					
						
							|  |  |  |              self.stretch_to_bounds | 
					
						
							| 
									
										
										
										
											2011-06-28 06:51:55 +00:00
										 |  |  |              ) | 
					
						
							| 
									
										
										
										
											2009-12-24 19:50:43 +00:00
										 |  |  |         return {'FINISHED'} | 
					
						
							| 
									
										
										
										
											2009-11-03 17:51:22 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-09 11:01:44 +00:00
										 |  |  |     def invoke(self, context, event): | 
					
						
							|  |  |  |         wm = context.window_manager | 
					
						
							|  |  |  |         return wm.invoke_props_dialog(self) | 
					
						
							| 
									
										
										
										
											2017-03-18 20:03:24 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | classes = ( | 
					
						
							|  |  |  |     SmartProject, | 
					
						
							| 
									
										
										
										
											2017-03-25 11:07:05 +11:00
										 |  |  | ) |