[Bf-extensions-cvs] [8db46434] master: Magic UV: Release v6.3
nutti
noreply at git.blender.org
Mon Aug 10 09:24:43 CEST 2020
Commit: 8db46434a4b25569372a7172f83733ec14dffb31
Author: nutti
Date: Mon Aug 10 16:07:26 2020 +0900
Branches: master
https://developer.blender.org/rBA8db46434a4b25569372a7172f83733ec14dffb31
Magic UV: Release v6.3
Added features
- Clip UV
Updated features
- World Scale UV
* Add option "Area Calculation Method"
* Add option "Only Selected"
- UVW
* Support multiple objects
- Select UV
* Support multiple objects
- UV Inspection
* Add Paint UV Island feature
* Support multiple objects
Other updates
- Fix bugs
- Optimization
===================================================================
M magic_uv/__init__.py
M magic_uv/common.py
M magic_uv/lib/__init__.py
M magic_uv/op/__init__.py
M magic_uv/op/align_uv.py
M magic_uv/op/align_uv_cursor.py
A magic_uv/op/clip_uv.py
M magic_uv/op/copy_paste_uv.py
M magic_uv/op/copy_paste_uv_object.py
M magic_uv/op/copy_paste_uv_uvedit.py
M magic_uv/op/flip_rotate_uv.py
M magic_uv/op/mirror_uv.py
M magic_uv/op/move_uv.py
M magic_uv/op/pack_uv.py
M magic_uv/op/preserve_uv_aspect.py
M magic_uv/op/select_uv.py
M magic_uv/op/smooth_uv.py
M magic_uv/op/texture_lock.py
M magic_uv/op/texture_projection.py
M magic_uv/op/texture_wrap.py
M magic_uv/op/transfer_uv.py
M magic_uv/op/unwrap_constraint.py
M magic_uv/op/uv_bounding_box.py
M magic_uv/op/uv_inspection.py
M magic_uv/op/uv_sculpt.py
M magic_uv/op/uvw.py
M magic_uv/op/world_scale_uv.py
M magic_uv/preferences.py
M magic_uv/properites.py
M magic_uv/ui/IMAGE_MT_uvs.py
M magic_uv/ui/VIEW3D_MT_object.py
M magic_uv/ui/VIEW3D_MT_uv_map.py
M magic_uv/ui/__init__.py
M magic_uv/ui/uvedit_copy_paste_uv.py
M magic_uv/ui/uvedit_editor_enhancement.py
M magic_uv/ui/uvedit_uv_manipulation.py
M magic_uv/ui/view3d_copy_paste_uv_editmode.py
M magic_uv/ui/view3d_copy_paste_uv_objectmode.py
M magic_uv/ui/view3d_uv_manipulation.py
M magic_uv/ui/view3d_uv_mapping.py
M magic_uv/updater.py
M magic_uv/utils/__init__.py
M magic_uv/utils/addon_updater.py
M magic_uv/utils/bl_class_registry.py
M magic_uv/utils/compatibility.py
M magic_uv/utils/property_class_registry.py
===================================================================
diff --git a/magic_uv/__init__.py b/magic_uv/__init__.py
index 8630038a..b92714fe 100644
--- a/magic_uv/__init__.py
+++ b/magic_uv/__init__.py
@@ -20,21 +20,23 @@
__author__ = "Nutti <nutti.metro at gmail.com>"
__status__ = "production"
-__version__ = "6.2"
-__date__ = "31 Jul 2019"
+__version__ = "6.3"
+__date__ = "10 Aug 2020"
bl_info = {
"name": "Magic UV",
"author": "Nutti, Mifth, Jace Priester, kgeogeo, mem, imdjs"
"Keith (Wahooney) Boshoff, McBuff, MaxRobinot, "
- "Alexander Milovsky",
- "version": (6, 2, 0),
+ "Alexander Milovsky, Dusan Stevanovic",
+ "version": (6, 3, 0),
"blender": (2, 80, 0),
"location": "See Add-ons Preferences",
"description": "UV Toolset. See Add-ons Preferences for details",
"warning": "",
"support": "COMMUNITY",
+ "wiki_url": "https://docs.blender.org/manual/en/dev/addons/"
+ "uv/magic_uv.html",
"doc_url": "{BLENDER_MANUAL_URL}/addons/uv/magic_uv.html",
"tracker_url": "https://github.com/nutti/Magic-UV",
"category": "UV",
diff --git a/magic_uv/common.py b/magic_uv/common.py
index df3597be..11696667 100644
--- a/magic_uv/common.py
+++ b/magic_uv/common.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro at gmail.com>"
__status__ = "production"
-__version__ = "6.2"
-__date__ = "31 Jul 2019"
+__version__ = "6.3"
+__date__ = "10 Aug 2020"
from collections import defaultdict
from pprint import pprint
@@ -244,15 +244,16 @@ def __parse_island(bm, face_idx, faces_left, island,
Parse island
"""
- if face_idx in faces_left:
- faces_left.remove(face_idx)
- island.append({'face': bm.faces[face_idx]})
- for v in face_to_verts[face_idx]:
- connected_faces = vert_to_faces[v]
- if connected_faces:
+ faces_to_parse = [face_idx]
+ while faces_to_parse:
+ fidx = faces_to_parse.pop(0)
+ if fidx in faces_left:
+ faces_left.remove(fidx)
+ island.append({'face': bm.faces[fidx]})
+ for v in face_to_verts[fidx]:
+ connected_faces = vert_to_faces[v]
for cf in connected_faces:
- __parse_island(bm, cf, faces_left, island, face_to_verts,
- vert_to_faces)
+ faces_to_parse.append(cf)
def __get_island(bm, face_to_verts, vert_to_faces):
@@ -351,18 +352,60 @@ def calc_polygon_3d_area(points):
return 0.5 * area
-def measure_mesh_area(obj):
+def get_faces_list(bm, method, only_selected):
+ faces_list = []
+ if method == 'MESH':
+ if only_selected:
+ faces_list.append([f for f in bm.faces if f.select])
+ else:
+ faces_list.append([f for f in bm.faces])
+ elif method == 'UV ISLAND':
+ if not bm.loops.layers.uv:
+ return None
+ uv_layer = bm.loops.layers.uv.verify()
+ if only_selected:
+ faces = [f for f in bm.faces if f.select]
+ islands = get_island_info_from_faces(bm, faces, uv_layer)
+ for isl in islands:
+ faces_list.append([f["face"] for f in isl["faces"]])
+ else:
+ faces = [f for f in bm.faces]
+ islands = get_island_info_from_faces(bm, faces, uv_layer)
+ for isl in islands:
+ faces_list.append([f["face"] for f in isl["faces"]])
+ elif method == 'FACE':
+ if only_selected:
+ for f in bm.faces:
+ if f.select:
+ faces_list.append([f])
+ else:
+ for f in bm.faces:
+ faces_list.append([f])
+ else:
+ raise ValueError("Invalid method: {}".format(method))
+
+ return faces_list
+
+
+def measure_mesh_area(obj, calc_method, only_selected):
bm = bmesh.from_edit_mesh(obj.data)
if check_version(2, 73, 0) >= 0:
bm.verts.ensure_lookup_table()
bm.edges.ensure_lookup_table()
bm.faces.ensure_lookup_table()
- sel_faces = [f for f in bm.faces if f.select]
+ faces_list = get_faces_list(bm, calc_method, only_selected)
- # measure
+ areas = []
+ for faces in faces_list:
+ areas.append(measure_mesh_area_from_faces(faces))
+
+ return areas
+
+
+def measure_mesh_area_from_faces(faces):
mesh_area = 0.0
- for f in sel_faces:
+ for f in faces:
verts = [l.vert.co for l in f.loops]
f_mesh_area = calc_polygon_3d_area(verts)
mesh_area = mesh_area + f_mesh_area
@@ -405,7 +448,7 @@ def find_image(obj, face=None, tex_layer=None):
if len(images) >= 2:
raise RuntimeError("Find more than 2 images")
- if len(images) == 0:
+ if not images:
return None
return images[0]
@@ -428,40 +471,26 @@ def find_images(obj, face=None, tex_layer=None):
return images
-def measure_uv_area(obj, method='FIRST', tex_size=None):
- bm = bmesh.from_edit_mesh(obj.data)
- if check_version(2, 73, 0) >= 0:
- bm.verts.ensure_lookup_table()
- bm.edges.ensure_lookup_table()
- bm.faces.ensure_lookup_table()
-
- if not bm.loops.layers.uv:
- return None
- uv_layer = bm.loops.layers.uv.verify()
-
- tex_layer = find_texture_layer(bm)
-
- sel_faces = [f for f in bm.faces if f.select]
-
- # measure
+def measure_uv_area_from_faces(obj, faces, uv_layer, tex_layer,
+ tex_selection_method, tex_size):
uv_area = 0.0
- for f in sel_faces:
+ for f in faces:
uvs = [l[uv_layer].uv for l in f.loops]
f_uv_area = calc_polygon_2d_area(uvs)
# user specified
- if method == 'USER_SPECIFIED' and tex_size is not None:
+ if tex_selection_method == 'USER_SPECIFIED' and tex_size is not None:
img_size = tex_size
# first texture if there are more than 2 textures assigned
# to the object
- elif method == 'FIRST':
+ elif tex_selection_method == 'FIRST':
img = find_image(obj, f, tex_layer)
# can not find from node, so we can not get texture size
if not img:
return None
img_size = img.size
# average texture size
- elif method == 'AVERAGE':
+ elif tex_selection_method == 'AVERAGE':
imgs = find_images(obj, f, tex_layer)
if not imgs:
return None
@@ -473,7 +502,7 @@ def measure_uv_area(obj, method='FIRST', tex_size=None):
img_size = [img_size_total[0] / len(imgs),
img_size_total[1] / len(imgs)]
# max texture size
- elif method == 'MAX':
+ elif tex_selection_method == 'MAX':
imgs = find_images(obj, f, tex_layer)
if not imgs:
return None
@@ -484,7 +513,7 @@ def measure_uv_area(obj, method='FIRST', tex_size=None):
max(img_size_max[1], img.size[1])]
img_size = img_size_max
# min texture size
- elif method == 'MIN':
+ elif tex_selection_method == 'MIN':
imgs = find_images(obj, f, tex_layer)
if not imgs:
return None
@@ -495,13 +524,40 @@ def measure_uv_area(obj, method='FIRST', tex_size=None):
min(img_size_min[1], img.size[1])]
img_size = img_size_min
else:
- raise RuntimeError("Unexpected method: {}".format(method))
+ raise RuntimeError("Unexpected method: {}"
+ .format(tex_selection_method))
- uv_area = uv_area + f_uv_area * img_size[0] * img_size[1]
+ uv_area += f_uv_area * img_size[0] * img_size[1]
return uv_area
+def measure_uv_area(obj, calc_method, tex_selection_method, tex_size,
+ only_selected):
+ bm = bmesh.from_edit_mesh(obj.data)
+ if check_version(2, 73, 0) >= 0:
+ bm.verts.ensure_lookup_table()
+ bm.edges.ensure_lookup_table()
+ bm.faces.ensure_lookup_table()
+
+ if not bm.loops.layers.uv:
+ return None
+ uv_layer = bm.loops.layers.uv.verify()
+ tex_layer = find_texture_layer(bm)
+ faces_list = get_faces_list(bm, calc_method, only_selected)
+
+ # measure
+ uv_areas = []
+ for faces in faces_list:
+ uv_area = measure_uv_area_from_faces(
+ obj, faces, uv_layer, tex_layer, tex_selection_method, tex_size)
+ if uv_area is None:
+ return None
+ uv_areas.append(uv_area)
+
+ return uv_areas
+
+
def diff_point_to_segment(a, b, p):
ab = b - a
normal_ab = ab.normalized()
@@ -520,43 +576,42 @@ def diff_point_to_segment(a, b, p):
# get selected loop pair whose loops are connected each other
def __get_loop_pairs(l, uv_layer):
-
- def __get_loop_pairs_internal(l_, pairs_, uv_layer_, parsed_):
- parsed_.append(l_)
- for ll in l_.vert.link_loops:
+ pairs = []
+ parsed = []
+ loops_ready = [l]
+ while loops_ready:
+ l = loops_ready.pop(0)
+ parsed.append(l)
+ for ll in l.vert.link_loops:
# forward direction
lln = ll.link_loop_next
# if there is same pair, skip it
found = False
- for p in pairs_:
+ for p in pairs:
if (ll in p) and (lln in p):
found = True
break
# two loops must be selected
- if ll[uv_layer_].select and lln[uv_layer_].select:
+ if ll[uv_layer].select and lln[uv_layer].select:
if not found:
- pairs_.append([ll, lln])
- if lln not in parsed_:
- __get_loop_pairs_internal(lln, pairs_, uv_layer_, parsed_)
+ pairs.append([ll, lln])
+ if (lln not in parsed) and (lln not in loops_ready):
+ loops_ready.append(lln)
# backward direction
llp = ll.link_loop_prev
# if there is same pair, skip it
found = False
- for p in pairs_:
+ for p in pairs:
if (ll in p) and (llp in p):
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-extensions-cvs
mailing list