[Bf-extensions-cvs] [2cbb9e2b] master: Magic UV: Release v6.6

nutti noreply at git.blender.org
Fri Apr 22 09:23:50 CEST 2022


Commit: 2cbb9e2b960ac343a6f5796e20d0efb443bd4a67
Author: nutti
Date:   Fri Apr 22 16:21:10 2022 +0900
Branches: master
https://developer.blender.org/rBA2cbb9e2b960ac343a6f5796e20d0efb443bd4a67

Magic UV: Release v6.6

Added Features

* Copy/Paste UV Island

Updated Features

* Pack UV
  * Add options "Accurate Island Copy", "Stride", "Apply Pack UV"

Other Updates

* Add 'develop' branch to the update target of updater
* Make documents official
* Fix bugs

===================================================================

M	magic_uv/__init__.py
M	magic_uv/common.py
M	magic_uv/lib/__init__.py
M	magic_uv/lib/bglx.py
M	magic_uv/op/__init__.py
M	magic_uv/op/align_uv.py
M	magic_uv/op/align_uv_cursor.py
M	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/properties.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/utils/__init__.py
M	magic_uv/utils/bl_class_registry.py
M	magic_uv/utils/compatibility.py
A	magic_uv/utils/graph.py
M	magic_uv/utils/property_class_registry.py

===================================================================

diff --git a/magic_uv/__init__.py b/magic_uv/__init__.py
index dc3c9641..88385107 100644
--- a/magic_uv/__init__.py
+++ b/magic_uv/__init__.py
@@ -4,16 +4,17 @@
 
 __author__ = "Nutti <nutti.metro at gmail.com>"
 __status__ = "production"
-__version__ = "6.5"
-__date__ = "6 Mar 2021"
+__version__ = "6.6"
+__date__ = "22 Apr 2022"
 
 
 bl_info = {
     "name": "Magic UV",
-    "author": "Nutti, Mifth, Jace Priester, kgeogeo, mem, imdjs"
+    "author": "Nutti, Mifth, Jace Priester, kgeogeo, mem, imdjs, "
               "Keith (Wahooney) Boshoff, McBuff, MaxRobinot, "
-              "Alexander Milovsky, Dusan Stevanovic, MatthiasThDs",
-    "version": (6, 5, 0),
+              "Alexander Milovsky, Dusan Stevanovic, MatthiasThDs, "
+              "theCryingMan, PratikBorhade302",
+    "version": (6, 6, 0),
     "blender": (2, 80, 0),
     "location": "See Add-ons Preferences",
     "description": "UV Toolset. See Add-ons Preferences for details",
diff --git a/magic_uv/common.py b/magic_uv/common.py
index 4e633408..034936c5 100644
--- a/magic_uv/common.py
+++ b/magic_uv/common.py
@@ -4,8 +4,8 @@
 
 __author__ = "Nutti <nutti.metro at gmail.com>"
 __status__ = "production"
-__version__ = "6.5"
-__date__ = "6 Mar 2021"
+__version__ = "6.6"
+__date__ = "22 Apr 2022"
 
 from collections import defaultdict
 from pprint import pprint
@@ -17,6 +17,7 @@ from mathutils import Vector
 import bmesh
 
 from .utils import compatibility as compat
+from .utils.graph import Graph, Node
 
 
 __DEBUG_MODE = False
@@ -286,6 +287,30 @@ def get_island_info(obj, only_selected=True):
     return get_island_info_from_bmesh(bm, only_selected)
 
 
+# Return island info.
+#
+# Format:
+#
+# [
+#   {
+#     faces: [
+#       {
+#         face: BMFace
+#         max_uv: Vector (2D)
+#         min_uv: Vector (2D)
+#         ave_uv: Vector (2D)
+#       },
+#       ...
+#     ]
+#     center: Vector (2D)
+#     size: Vector (2D)
+#     num_uv: int
+#     group: int
+#     max: Vector (2D)
+#     min: Vector (2D)
+#   },
+#   ...
+# ]
 def get_island_info_from_bmesh(bm, only_selected=True):
     if not bm.loops.layers.uv:
         return None
@@ -1184,12 +1209,22 @@ def __is_polygon_flipped(points):
 
 
 def __is_point_in_polygon(point, subject_points):
+    """Return true when point is inside of the polygon by using
+    'Crossing number algorithm'.
+    """
+
     count = 0
     for i in range(len(subject_points)):
         uv_start1 = subject_points.get(i)
         uv_end1 = subject_points.get(i + 1)
         uv_start2 = point
         uv_end2 = Vector((1000000.0, point.y))
+
+        # If the point exactly matches to the point of the polygon,
+        # this point is not in polygon.
+        if uv_start1.x == uv_start2.x and uv_start1.y == uv_start2.y:
+            return False
+
         intersected, _ = __is_segment_intersect(uv_start1, uv_end1,
                                                 uv_start2, uv_end2)
         if intersected:
@@ -1239,7 +1274,7 @@ def get_overlapped_uv_info(bm_list, faces_list, uv_layer_list,
             overlapped_uv_layer_pairs.append([uv_layer_1, uv_layer_2])
             overlapped_bm_paris.append([bm_1, bm_2])
 
-    # next, check polygon overlapped
+    # check polygon overlapped (inter UV islands)
     overlapped_uvs = []
     for oip, uvlp, bmp in zip(overlapped_isl_pairs,
                               overlapped_uv_layer_pairs,
@@ -1272,6 +1307,41 @@ def get_overlapped_uv_info(bm_list, faces_list, uv_layer_list,
                                            "subject_uvs": subject_uvs,
                                            "polygons": polygons})
 
+    # check polygon overlapped (intra UV island)
+    for info, uv_layer, bm in isl:
+        for i in range(len(info["faces"])):
+            clip = info["faces"][i]
+            f_clip = clip["face"]
+            clip_uvs = [l[uv_layer].uv.copy() for l in f_clip.loops]
+            for j in range(len(info["faces"])):
+                if j <= i:
+                    continue
+
+                subject = info["faces"][j]
+                f_subject = subject["face"]
+
+                # fast operation, apply bounding box algorithm
+                if (clip["max_uv"].x < subject["min_uv"].x) or \
+                   (subject["max_uv"].x < clip["min_uv"].x) or \
+                   (clip["max_uv"].y < subject["min_uv"].y) or \
+                   (subject["max_uv"].y < clip["min_uv"].y):
+                    continue
+
+                subject_uvs = [l[uv_layer].uv.copy() for l in f_subject.loops]
+                # slow operation, apply Weiler-Atherton cliping algorithm
+                result, polygons = \
+                    __do_weiler_atherton_cliping(clip_uvs, subject_uvs,
+                                                 mode, same_polygon_threshold)
+                if result:
+                    overlapped_uvs.append({"clip_bmesh": bm,
+                                           "subject_bmesh": bm,
+                                           "clip_face": f_clip,
+                                           "subject_face": f_subject,
+                                           "clip_uv_layer": uv_layer,
+                                           "subject_uv_layer": uv_layer,
+                                           "subject_uvs": subject_uvs,
+                                           "polygons": polygons})
+
     return overlapped_uvs
 
 
@@ -1308,3 +1378,64 @@ def __is_polygon_same(points1, points2, threshold):
             return False
 
     return True
+
+
+def _is_uv_loop_connected(l1, l2, uv_layer):
+    uv1 = l1[uv_layer].uv
+    uv2 = l2[uv_layer].uv
+    return uv1.x == uv2.x and uv1.y == uv2.y
+
+
+def create_uv_graph(loops, uv_layer):
+    # For looking up faster.
+    loop_index_to_loop = {}     # { loop index: loop }
+    for l in loops:
+        loop_index_to_loop[l.index] = l
+
+    # Setup relationship between uv_vert and loops.
+    # uv_vert is a representative of the loops which shares same
+    # UV coordinate.
+    uv_vert_to_loops = {}   # { uv_vert: loops belonged to uv_vert }
+    loop_to_uv_vert = {}    # { loop: uv_vert belonged to }
+    for l in loops:
+        found = False
+        for k in uv_vert_to_loops.keys():
+            if _is_uv_loop_connected(k, l, uv_layer):
+                uv_vert_to_loops[k].append(l)
+                loop_to_uv_vert[l] = k
+                found = True
+                break
+        if not found:
+            uv_vert_to_loops[l] = [l]
+            loop_to_uv_vert[l] = l
+
+    # Collect adjacent uv_vert.
+    uv_adj_verts = {}       # { uv_vert: adj uv_vert list }
+    for v, vs in uv_vert_to_loops.items():
+        uv_adj_verts[v] = []
+        for ll in vs:
+            ln = ll.link_loop_next
+            lp = ll.link_loop_prev
+            uv_adj_verts[v].append(loop_to_uv_vert[ln])
+            uv_adj_verts[v].append(loop_to_uv_vert[lp])
+        uv_adj_verts[v] = list(set(uv_adj_verts[v]))
+
+    # Setup uv_vert graph.
+    graph = Graph()
+    for v in uv_adj_verts.keys():
+        graph.add_node(
+            Node(v.index, {"uv_vert": v, "loops": uv_vert_to_loops[v]})
+        )
+    edges = []
+    for v, adjs in uv_adj_verts.items():
+        n1 = graph.get_node(v.index)
+        for a in adjs:
+            n2 = graph.get_node(a.index)
+            edges.append(tuple(sorted((n1.key, n2.key))))
+    edges = list(set(edges))
+    for e in edges:
+        n1 = graph.get_node(e[0])
+        n2 = graph.get_node(e[1])
+        graph.add_edge(n1, n2)
+
+    return graph
diff --git a/magic_uv/lib/__init__.py b/magic_uv/lib/__init__.py
index 76eaf480..bccf4e17 100644
--- a/magic_uv/lib/__init__.py
+++ b/magic_uv/lib/__init__.py
@@ -4,8 +4,8 @@
 
 __author__ = "Nutti <nutti.metro at gmail.com>"
 __status__ = "production"
-__version__ = "6.5"
-__date__ = "6 Mar 2021"
+__version__ = "6.6"
+__date__ = "22 Apr 2022"
 
 if "bpy" in locals():
     import importlib
diff --git a/magic_uv/lib/bglx.py b/magic_uv/lib/bglx.py
index c1f696ab..044141b6 100644
--- a/magic_uv/lib/bglx.py
+++ b/magic_uv/lib/bglx.py
@@ -1,5 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-or-later
 
+# <pep8-80 compliant>
+
 from threading import Lock
 
 import bgl
diff --git a/magic_uv/op/__init__.py b/magic_uv/op/__init__.py
index da77b17b..223ed004 100644
--- a/magic_uv/op/__init__.py
+++ b/magic_uv/op/__init__.py
@@ -4,8 +4,8 @@
 
 __author__ = "Nutti <nutti.metro at gmail.com>"
 __status__ = "production"
-__version__ = "6.5"
-__date__ = "6 Mar 2021"
+__version__ = "6.6"
+__date__ = "22 Apr 2022"
 
 if "bpy" in locals():
     import importlib
diff --git a/magic_uv/op/align_uv.py b/magic_uv/op/align_uv.py
index 9f606db9..cf5a49de 100644
--- a/magic_uv/op/align_uv.py
+++ b/magic_uv/op/align_uv.py
@@ -4,8 +4,8 @@
 
 __author__ = "imdjs, Nutti <nutti.metro at gmail.com>"
 __status__ = "production"
-__version__ = "6.5"
-__date__ = "6 Mar 2021"
+__version__ = "6.6"
+__date__ = "22 Apr 2022"
 
 import math
 from math import atan2, tan, sin, cos
@@ -28,6 +28,12 @@ from .. import common
 
 
 def _is_valid_context(context):
+    # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
+    # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
+    # after the execution
+    if not common.is_valid_space(context, ['IMAGE_EDITOR', 'VIEW_3D']):
+        return False
+
     objs = common.get_uv_editable_objects(context)
     if not objs:
         return False
@@ -36,12 +42,6 @@ def _is_valid_context(context):
     if context.object.mode != 'EDIT':
         return False
 
-    # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
-    # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
-    # after the execution
-    if not common.is_valid_space(context, ['IMAGE_EDITOR', 'VIEW_3D']):
-        return False
-
     return True
 
 
diff --git a/magic_uv/op/align_uv_cursor.py b/magic_uv/op/align_uv_cursor.py
index 2b7f1491..696b7cb8 100644
--- a/magic_uv/op/align_uv_cursor.py
+++ b/magic_uv/op/align_uv_cursor.py
@@ -4,8 +4,8 @@
 
 __author__ = "Nutti <nutti.metro at gmail.com>"
 __status__ = "production"
-__version__ = "6.5"
-__date__ = "6 Mar 2021"
+__version__ = "6.6"
+__date__ = "22 Apr 2022"
 
 import bpy
 from mathutils import Vector
@

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-extensions-cvs mailing list