Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'uv_magic_uv/op/copy_paste_uv.py')
-rw-r--r--uv_magic_uv/op/copy_paste_uv.py744
1 files changed, 312 insertions, 432 deletions
diff --git a/uv_magic_uv/op/copy_paste_uv.py b/uv_magic_uv/op/copy_paste_uv.py
index ee89b5e9..23bc8343 100644
--- a/uv_magic_uv/op/copy_paste_uv.py
+++ b/uv_magic_uv/op/copy_paste_uv.py
@@ -18,121 +18,179 @@
#
# ##### END GPL LICENSE BLOCK #####
-__author__ = "imdjs, Nutti <nutti.metro@gmail.com>"
+__author__ = "Nutti <nutti.metro@gmail.com>, Jace Priester"
__status__ = "production"
-__version__ = "5.1"
-__date__ = "24 Feb 2018"
+__version__ = "5.2"
+__date__ = "17 Nov 2018"
-import math
-from math import atan2, sin, cos
-import bpy
import bmesh
+import bpy.utils
from bpy.props import (
StringProperty,
BoolProperty,
IntProperty,
EnumProperty,
)
-from mathutils import Vector
+from ..impl import copy_paste_uv_impl as impl
from .. import common
+from ..utils.bl_class_registry import BlClassRegistry
+from ..utils.property_class_registry import PropertyClassRegistry
+
+__all__ = [
+ 'Properties',
+ 'MUV_OT_CopyPasteUV_CopyUV',
+ 'MUV_MT_CopyPasteUV_CopyUV',
+ 'MUV_OT_CopyPasteUV_PasteUV',
+ 'MUV_MT_CopyPasteUV_PasteUV',
+ 'MUV_OT_CopyPasteUV_SelSeqCopyUV',
+ 'MUV_MT_CopyPasteUV_SelSeqCopyUV',
+ 'MUV_OT_CopyPasteUV_SelSeqPasteUV',
+ 'MUV_MT_CopyPasteUV_SelSeqPasteUV',
+]
+
+
+@PropertyClassRegistry()
+class Properties:
+ idname = "copy_paste_uv"
+
+ @classmethod
+ def init_props(cls, scene):
+ class Props():
+ src_info = None
+
+ scene.muv_props.copy_paste_uv = Props()
+ scene.muv_props.copy_paste_uv_selseq = Props()
+
+ scene.muv_copy_paste_uv_enabled = BoolProperty(
+ name="Copy/Paste UV Enabled",
+ description="Copy/Paste UV is enabled",
+ default=False
+ )
+ scene.muv_copy_paste_uv_copy_seams = BoolProperty(
+ name="Seams",
+ description="Copy Seams",
+ default=True
+ )
+ scene.muv_copy_paste_uv_mode = EnumProperty(
+ items=[
+ ('DEFAULT', "Default", "Default Mode"),
+ ('SEL_SEQ', "Selection Sequence", "Selection Sequence Mode")
+ ],
+ name="Copy/Paste UV Mode",
+ description="Copy/Paste UV Mode",
+ default='DEFAULT'
+ )
+ scene.muv_copy_paste_uv_strategy = EnumProperty(
+ name="Strategy",
+ description="Paste Strategy",
+ items=[
+ ('N_N', 'N:N', 'Number of faces must be equal to source'),
+ ('N_M', 'N:M', 'Number of faces must not be equal to source')
+ ],
+ default='N_M'
+ )
+
+ @classmethod
+ def del_props(cls, scene):
+ del scene.muv_props.copy_paste_uv
+ del scene.muv_props.copy_paste_uv_selseq
+ del scene.muv_copy_paste_uv_enabled
+ del scene.muv_copy_paste_uv_copy_seams
+ del scene.muv_copy_paste_uv_mode
+ del scene.muv_copy_paste_uv_strategy
-class MUV_CPUVCopyUV(bpy.types.Operator):
+@BlClassRegistry()
+class MUV_OT_CopyPasteUV_CopyUV(bpy.types.Operator):
"""
Operation class: Copy UV coordinate
"""
- bl_idname = "uv.muv_cpuv_copy_uv"
- bl_label = "Copy UV (Operation)"
- bl_description = "Copy UV coordinate (Operation)"
+ bl_idname = "uv.muv_copy_paste_uv_operator_copy_uv"
+ bl_label = "Copy UV"
+ bl_description = "Copy UV coordinate"
bl_options = {'REGISTER', 'UNDO'}
- uv_map = StringProperty(options={'HIDDEN'})
+ uv_map: StringProperty(default="__default", options={'HIDDEN'})
+
+ @classmethod
+ def poll(cls, context):
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return True
+ return impl.is_valid_context(context)
def execute(self, context):
- props = context.scene.muv_props.cpuv
- if self.uv_map == "":
- self.report({'INFO'}, "Copy UV coordinate")
- else:
- self.report(
- {'INFO'}, "Copy UV coordinate (UV map:%s)" % (self.uv_map))
+ props = context.scene.muv_props.copy_paste_uv
obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
+ bm = common.create_bmesh(obj)
# get UV layer
- if self.uv_map == "":
- if not bm.loops.layers.uv:
- self.report(
- {'WARNING'}, "Object must have more than one UV map")
- return {'CANCELLED'}
- uv_layer = bm.loops.layers.uv.verify()
- else:
- uv_layer = bm.loops.layers.uv[self.uv_map]
+ uv_layers = impl.get_copy_uv_layers(self, bm, self.uv_map)
+ if not uv_layers:
+ return {'CANCELLED'}
# get selected face
- props.src_uvs = []
- props.src_pin_uvs = []
- props.src_seams = []
- for face in bm.faces:
- if face.select:
- uvs = [l[uv_layer].uv.copy() for l in face.loops]
- pin_uvs = [l[uv_layer].pin_uv for l in face.loops]
- seams = [l.edge.seam for l in face.loops]
- props.src_uvs.append(uvs)
- props.src_pin_uvs.append(pin_uvs)
- props.src_seams.append(seams)
- if not props.src_uvs or not props.src_pin_uvs:
- self.report({'WARNING'}, "No faces are selected")
+ src_info = impl.get_src_face_info(self, bm, uv_layers)
+ if src_info is None:
return {'CANCELLED'}
- self.report({'INFO'}, "%d face(s) are selected" % len(props.src_uvs))
+ props.src_info = src_info
+
+ face_count = len(props.src_info[list(props.src_info.keys())[0]])
+ self.report({'INFO'}, "{} face(s) are copied".format(face_count))
return {'FINISHED'}
-class MUV_CPUVCopyUVMenu(bpy.types.Menu):
+@BlClassRegistry()
+class MUV_MT_CopyPasteUV_CopyUV(bpy.types.Menu):
"""
Menu class: Copy UV coordinate
"""
- bl_idname = "uv.muv_cpuv_copy_uv_menu"
- bl_label = "Copy UV"
- bl_description = "Copy UV coordinate"
+ bl_idname = "uv.muv_copy_paste_uv_menu_copy_uv"
+ bl_label = "Copy UV (Menu)"
+ bl_description = "Menu of Copy UV coordinate"
+
+ @classmethod
+ def poll(cls, context):
+ return impl.is_valid_context(context)
def draw(self, context):
layout = self.layout
# create sub menu
obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
+ bm = common.create_bmesh(obj)
uv_maps = bm.loops.layers.uv.keys()
- layout.operator(
- MUV_CPUVCopyUV.bl_idname,
- text="[Default]",
- icon="IMAGE_COL"
- ).uv_map = ""
+
+ ops = layout.operator(MUV_OT_CopyPasteUV_CopyUV.bl_idname,
+ text="[Default]")
+ ops.uv_map = "__default"
+
+ ops = layout.operator(MUV_OT_CopyPasteUV_CopyUV.bl_idname,
+ text="[All]")
+ ops.uv_map = "__all"
+
for m in uv_maps:
- layout.operator(
- MUV_CPUVCopyUV.bl_idname,
- text=m,
- icon="IMAGE_COL"
- ).uv_map = m
+ ops = layout.operator(MUV_OT_CopyPasteUV_CopyUV.bl_idname, text=m)
+ ops.uv_map = m
-class MUV_CPUVPasteUV(bpy.types.Operator):
+@BlClassRegistry()
+class MUV_OT_CopyPasteUV_PasteUV(bpy.types.Operator):
"""
Operation class: Paste UV coordinate
"""
- bl_idname = "uv.muv_cpuv_paste_uv"
- bl_label = "Paste UV (Operation)"
- bl_description = "Paste UV coordinate (Operation)"
+ bl_idname = "uv.muv_copy_paste_uv_operator_paste_uv"
+ bl_label = "Paste UV"
+ bl_description = "Paste UV coordinate"
bl_options = {'REGISTER', 'UNDO'}
- uv_map = StringProperty(options={'HIDDEN'})
- strategy = EnumProperty(
+ uv_map: StringProperty(default="__default", options={'HIDDEN'})
+ strategy: EnumProperty(
name="Strategy",
description="Paste Strategy",
items=[
@@ -141,353 +199,209 @@ class MUV_CPUVPasteUV(bpy.types.Operator):
],
default="N_M"
)
- flip_copied_uv = BoolProperty(
+ flip_copied_uv: BoolProperty(
name="Flip Copied UV",
description="Flip Copied UV...",
default=False
)
- rotate_copied_uv = IntProperty(
+ rotate_copied_uv: IntProperty(
default=0,
name="Rotate Copied UV",
min=0,
max=30
)
- copy_seams = BoolProperty(
- name="Copy Seams",
+ copy_seams: BoolProperty(
+ name="Seams",
description="Copy Seams",
default=True
)
+ @classmethod
+ def poll(cls, context):
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return True
+ sc = context.scene
+ props = sc.muv_props.copy_paste_uv
+ if not props.src_info:
+ return False
+ return impl.is_valid_context(context)
+
def execute(self, context):
- props = context.scene.muv_props.cpuv
- if not props.src_uvs or not props.src_pin_uvs:
+ props = context.scene.muv_props.copy_paste_uv
+ if not props.src_info:
self.report({'WARNING'}, "Need copy UV at first")
return {'CANCELLED'}
- if self.uv_map == "":
- self.report({'INFO'}, "Paste UV coordinate")
- else:
- self.report(
- {'INFO'}, "Paste UV coordinate (UV map:%s)" % (self.uv_map))
obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
+ bm = common.create_bmesh(obj)
# get UV layer
- if self.uv_map == "":
- if not bm.loops.layers.uv:
- self.report(
- {'WARNING'}, "Object must have more than one UV map")
- return {'CANCELLED'}
- uv_layer = bm.loops.layers.uv.verify()
- else:
- uv_layer = bm.loops.layers.uv[self.uv_map]
+ uv_layers = impl.get_paste_uv_layers(self, obj, bm, props.src_info,
+ self.uv_map)
+ if not uv_layers:
+ return {'CANCELLED'}
# get selected face
- dest_uvs = []
- dest_pin_uvs = []
- dest_seams = []
- dest_face_indices = []
- for face in bm.faces:
- if face.select:
- dest_face_indices.append(face.index)
- uvs = [l[uv_layer].uv.copy() for l in face.loops]
- pin_uvs = [l[uv_layer].pin_uv for l in face.loops]
- seams = [l.edge.seam for l in face.loops]
- dest_uvs.append(uvs)
- dest_pin_uvs.append(pin_uvs)
- dest_seams.append(seams)
- if not dest_uvs or not dest_pin_uvs:
- self.report({'WARNING'}, "No faces are selected")
- return {'CANCELLED'}
- if self.strategy == 'N_N' and len(props.src_uvs) != len(dest_uvs):
- self.report(
- {'WARNING'},
- "Number of selected faces is different from copied" +
- "(src:%d, dest:%d)" %
- (len(props.src_uvs), len(dest_uvs)))
+ dest_info = impl.get_dest_face_info(self, bm, uv_layers,
+ props.src_info, self.strategy)
+ if dest_info is None:
return {'CANCELLED'}
# paste
- for i, idx in enumerate(dest_face_indices):
- suv = None
- spuv = None
- ss = None
- duv = None
- if self.strategy == 'N_N':
- suv = props.src_uvs[i]
- spuv = props.src_pin_uvs[i]
- ss = props.src_seams[i]
- duv = dest_uvs[i]
- elif self.strategy == 'N_M':
- suv = props.src_uvs[i % len(props.src_uvs)]
- spuv = props.src_pin_uvs[i % len(props.src_pin_uvs)]
- ss = props.src_seams[i % len(props.src_seams)]
- duv = dest_uvs[i]
- if len(suv) != len(duv):
- self.report({'WARNING'}, "Some faces are different size")
- return {'CANCELLED'}
- suvs_fr = [uv for uv in suv]
- spuvs_fr = [pin_uv for pin_uv in spuv]
- ss_fr = [s for s in ss]
- # flip UVs
- if self.flip_copied_uv is True:
- suvs_fr.reverse()
- spuvs_fr.reverse()
- ss_fr.reverse()
- # rotate UVs
- for _ in range(self.rotate_copied_uv):
- uv = suvs_fr.pop()
- pin_uv = spuvs_fr.pop()
- s = ss_fr.pop()
- suvs_fr.insert(0, uv)
- spuvs_fr.insert(0, pin_uv)
- ss_fr.insert(0, s)
- # paste UVs
- for l, suv, spuv, ss in zip(bm.faces[idx].loops, suvs_fr,
- spuvs_fr, ss_fr):
- l[uv_layer].uv = suv
- l[uv_layer].pin_uv = spuv
- if self.copy_seams is True:
- l.edge.seam = ss
- self.report({'INFO'}, "%d face(s) are copied" % len(dest_uvs))
+ ret = impl.paste_uv(self, bm, props.src_info, dest_info, uv_layers,
+ self.strategy, self.flip_copied_uv,
+ self.rotate_copied_uv, self.copy_seams)
+ if ret:
+ return {'CANCELLED'}
+
+ face_count = len(props.src_info[list(dest_info.keys())[0]])
+ self.report({'INFO'}, "{} face(s) are pasted".format(face_count))
bmesh.update_edit_mesh(obj.data)
- if self.copy_seams is True:
- obj.data.show_edge_seams = True
return {'FINISHED'}
-class MUV_CPUVPasteUVMenu(bpy.types.Menu):
+@BlClassRegistry()
+class MUV_MT_CopyPasteUV_PasteUV(bpy.types.Menu):
"""
Menu class: Paste UV coordinate
"""
- bl_idname = "uv.muv_cpuv_paste_uv_menu"
- bl_label = "Paste UV"
- bl_description = "Paste UV coordinate"
+ bl_idname = "uv.muv_copy_paste_uv_menu_paste_uv"
+ bl_label = "Paste UV (Menu)"
+ bl_description = "Menu of Paste UV coordinate"
+
+ @classmethod
+ def poll(cls, context):
+ sc = context.scene
+ props = sc.muv_props.copy_paste_uv
+ if not props.src_info:
+ return False
+ return impl.is_valid_context(context)
def draw(self, context):
sc = context.scene
layout = self.layout
# create sub menu
obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
+ bm = common.create_bmesh(obj)
uv_maps = bm.loops.layers.uv.keys()
- ops = layout.operator(MUV_CPUVPasteUV.bl_idname, text="[Default]")
- ops.uv_map = ""
- ops.copy_seams = sc.muv_cpuv_copy_seams
- ops.strategy = sc.muv_cpuv_strategy
+
+ ops = layout.operator(MUV_OT_CopyPasteUV_PasteUV.bl_idname,
+ text="[Default]")
+ ops.uv_map = "__default"
+ ops.copy_seams = sc.muv_copy_paste_uv_copy_seams
+ ops.strategy = sc.muv_copy_paste_uv_strategy
+
+ ops = layout.operator(MUV_OT_CopyPasteUV_PasteUV.bl_idname,
+ text="[New]")
+ ops.uv_map = "__new"
+ ops.copy_seams = sc.muv_copy_paste_uv_copy_seams
+ ops.strategy = sc.muv_copy_paste_uv_strategy
+
+ ops = layout.operator(MUV_OT_CopyPasteUV_PasteUV.bl_idname,
+ text="[All]")
+ ops.uv_map = "__all"
+ ops.copy_seams = sc.muv_copy_paste_uv_copy_seams
+ ops.strategy = sc.muv_copy_paste_uv_strategy
+
for m in uv_maps:
- ops = layout.operator(MUV_CPUVPasteUV.bl_idname, text=m)
+ ops = layout.operator(MUV_OT_CopyPasteUV_PasteUV.bl_idname, text=m)
ops.uv_map = m
- ops.copy_seams = sc.muv_cpuv_copy_seams
- ops.strategy = sc.muv_cpuv_strategy
+ ops.copy_seams = sc.muv_copy_paste_uv_copy_seams
+ ops.strategy = sc.muv_copy_paste_uv_strategy
-class MUV_CPUVIECopyUV(bpy.types.Operator):
+@BlClassRegistry()
+class MUV_OT_CopyPasteUV_SelSeqCopyUV(bpy.types.Operator):
"""
- Operation class: Copy UV coordinate on UV/Image Editor
+ Operation class: Copy UV coordinate by selection sequence
"""
- bl_idname = "uv.muv_cpuv_ie_copy_uv"
- bl_label = "Copy UV"
- bl_description = "Copy UV coordinate (only selected in UV/Image Editor)"
+ bl_idname = "uv.muv_copy_paste_uv_operator_selseq_copy_uv"
+ bl_label = "Copy UV (Selection Sequence)"
+ bl_description = "Copy UV data by selection sequence"
bl_options = {'REGISTER', 'UNDO'}
- @classmethod
- def poll(cls, context):
- return context.mode == 'EDIT_MESH'
-
- def execute(self, context):
- props = context.scene.muv_props.cpuv
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- uv_layer = bm.loops.layers.uv.verify()
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
-
- for face in bm.faces:
- if not face.select:
- continue
- skip = False
- for l in face.loops:
- if not l[uv_layer].select:
- skip = True
- break
- if skip:
- continue
- props.src_uvs.append([l[uv_layer].uv.copy() for l in face.loops])
-
- return {'FINISHED'}
-
-
-class MUV_CPUVIEPasteUV(bpy.types.Operator):
- """
- Operation class: Paste UV coordinate on UV/Image Editor
- """
-
- bl_idname = "uv.muv_cpuv_ie_paste_uv"
- bl_label = "Paste UV"
- bl_description = "Paste UV coordinate (only selected in UV/Image Editor)"
- bl_options = {'REGISTER', 'UNDO'}
+ uv_map: StringProperty(default="__default", options={'HIDDEN'})
@classmethod
def poll(cls, context):
- return context.mode == 'EDIT_MESH'
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return True
+ return impl.is_valid_context(context)
def execute(self, context):
- props = context.scene.muv_props.cpuv
+ props = context.scene.muv_props.copy_paste_uv_selseq
obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- uv_layer = bm.loops.layers.uv.verify()
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
-
- dest_uvs = []
- dest_face_indices = []
- for face in bm.faces:
- if not face.select:
- continue
- skip = False
- for l in face.loops:
- if not l[uv_layer].select:
- skip = True
- break
- if skip:
- continue
- dest_face_indices.append(face.index)
- uvs = [l[uv_layer].uv.copy() for l in face.loops]
- dest_uvs.append(uvs)
-
- for suvs, duvs in zip(props.src_uvs, dest_uvs):
- src_diff = suvs[1] - suvs[0]
- dest_diff = duvs[1] - duvs[0]
-
- src_base = suvs[0]
- dest_base = duvs[0]
-
- src_rad = atan2(src_diff.y, src_diff.x)
- dest_rad = atan2(dest_diff.y, dest_diff.x)
- if src_rad < dest_rad:
- radian = dest_rad - src_rad
- elif src_rad > dest_rad:
- radian = math.pi * 2 - (src_rad - dest_rad)
- else: # src_rad == dest_rad
- radian = 0.0
-
- ratio = dest_diff.length / src_diff.length
- break
-
- for suvs, fidx in zip(props.src_uvs, dest_face_indices):
- for l, suv in zip(bm.faces[fidx].loops, suvs):
- base = suv - src_base
- radian_ref = atan2(base.y, base.x)
- radian_fin = (radian + radian_ref)
- length = base.length
- turn = Vector((length * cos(radian_fin),
- length * sin(radian_fin)))
- target_uv = Vector((turn.x * ratio, turn.y * ratio)) + \
- dest_base
- l[uv_layer].uv = target_uv
-
- bmesh.update_edit_mesh(obj.data)
-
- return {'FINISHED'}
-
-
-class MUV_CPUVSelSeqCopyUV(bpy.types.Operator):
- """
- Operation class: Copy UV coordinate by selection sequence
- """
-
- bl_idname = "uv.muv_cpuv_selseq_copy_uv"
- bl_label = "Copy UV (Selection Sequence) (Operation)"
- bl_description = "Copy UV data by selection sequence (Operation)"
- bl_options = {'REGISTER', 'UNDO'}
-
- uv_map = StringProperty(options={'HIDDEN'})
-
- def execute(self, context):
- props = context.scene.muv_props.cpuv_selseq
- if self.uv_map == "":
- self.report({'INFO'}, "Copy UV coordinate (selection sequence)")
- else:
- self.report(
- {'INFO'},
- "Copy UV coordinate (selection sequence) (UV map:%s)"
- % (self.uv_map))
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
+ bm = common.create_bmesh(obj)
# get UV layer
- if self.uv_map == "":
- if not bm.loops.layers.uv:
- self.report(
- {'WARNING'}, "Object must have more than one UV map")
- return {'CANCELLED'}
- uv_layer = bm.loops.layers.uv.verify()
- else:
- uv_layer = bm.loops.layers.uv[self.uv_map]
+ uv_layers = impl.get_copy_uv_layers(self, bm, self.uv_map)
+ if not uv_layers:
+ return {'CANCELLED'}
# get selected face
- props.src_uvs = []
- props.src_pin_uvs = []
- props.src_seams = []
- for hist in bm.select_history:
- if isinstance(hist, bmesh.types.BMFace) and hist.select:
- uvs = [l[uv_layer].uv.copy() for l in hist.loops]
- pin_uvs = [l[uv_layer].pin_uv for l in hist.loops]
- seams = [l.edge.seam for l in hist.loops]
- props.src_uvs.append(uvs)
- props.src_pin_uvs.append(pin_uvs)
- props.src_seams.append(seams)
- if not props.src_uvs or not props.src_pin_uvs:
- self.report({'WARNING'}, "No faces are selected")
+ src_info = impl.get_select_history_src_face_info(self, bm, uv_layers)
+ if src_info is None:
return {'CANCELLED'}
- self.report({'INFO'}, "%d face(s) are selected" % len(props.src_uvs))
+ props.src_info = src_info
+
+ face_count = len(props.src_info[list(props.src_info.keys())[0]])
+ self.report({'INFO'}, "{} face(s) are selected".format(face_count))
return {'FINISHED'}
-class MUV_CPUVSelSeqCopyUVMenu(bpy.types.Menu):
+@BlClassRegistry()
+class MUV_MT_CopyPasteUV_SelSeqCopyUV(bpy.types.Menu):
"""
Menu class: Copy UV coordinate by selection sequence
"""
- bl_idname = "uv.muv_cpuv_selseq_copy_uv_menu"
- bl_label = "Copy UV (Selection Sequence)"
- bl_description = "Copy UV coordinate by selection sequence"
+ bl_idname = "uv.muv_copy_paste_uv_menu_selseq_copy_uv"
+ bl_label = "Copy UV (Selection Sequence) (Menu)"
+ bl_description = "Menu of Copy UV coordinate by selection sequence"
+
+ @classmethod
+ def poll(cls, context):
+ return impl.is_valid_context(context)
def draw(self, context):
layout = self.layout
obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
+ bm = common.create_bmesh(obj)
uv_maps = bm.loops.layers.uv.keys()
- layout.operator(
- MUV_CPUVSelSeqCopyUV.bl_idname,
- text="[Default]", icon="IMAGE_COL").uv_map = ""
+
+ ops = layout.operator(MUV_OT_CopyPasteUV_SelSeqCopyUV.bl_idname,
+ text="[Default]")
+ ops.uv_map = "__default"
+
+ ops = layout.operator(MUV_OT_CopyPasteUV_SelSeqCopyUV.bl_idname,
+ text="[All]")
+ ops.uv_map = "__all"
+
for m in uv_maps:
- layout.operator(
- MUV_CPUVSelSeqCopyUV.bl_idname,
- text=m, icon="IMAGE_COL").uv_map = m
+ ops = layout.operator(MUV_OT_CopyPasteUV_SelSeqCopyUV.bl_idname,
+ text=m)
+ ops.uv_map = m
-class MUV_CPUVSelSeqPasteUV(bpy.types.Operator):
+@BlClassRegistry()
+class MUV_OT_CopyPasteUV_SelSeqPasteUV(bpy.types.Operator):
"""
Operation class: Paste UV coordinate by selection sequence
"""
- bl_idname = "uv.muv_cpuv_selseq_paste_uv"
- bl_label = "Paste UV (Selection Sequence) (Operation)"
- bl_description = "Paste UV coordinate by selection sequence (Operation)"
+ bl_idname = "uv.muv_copy_paste_uv_operator_selseq_paste_uv"
+ bl_label = "Paste UV (Selection Sequence)"
+ bl_description = "Paste UV coordinate by selection sequence"
bl_options = {'REGISTER', 'UNDO'}
- uv_map = StringProperty(options={'HIDDEN'})
- strategy = EnumProperty(
+ uv_map: StringProperty(default="__default", options={'HIDDEN'})
+ strategy: EnumProperty(
name="Strategy",
description="Paste Strategy",
items=[
@@ -496,151 +410,117 @@ class MUV_CPUVSelSeqPasteUV(bpy.types.Operator):
],
default="N_M"
)
- flip_copied_uv = BoolProperty(
+ flip_copied_uv: BoolProperty(
name="Flip Copied UV",
description="Flip Copied UV...",
default=False
)
- rotate_copied_uv = IntProperty(
+ rotate_copied_uv: IntProperty(
default=0,
name="Rotate Copied UV",
min=0,
max=30
)
- copy_seams = BoolProperty(
- name="Copy Seams",
+ copy_seams: BoolProperty(
+ name="Seams",
description="Copy Seams",
default=True
)
+ @classmethod
+ def poll(cls, context):
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return True
+ sc = context.scene
+ props = sc.muv_props.copy_paste_uv_selseq
+ if not props.src_info:
+ return False
+ return impl.is_valid_context(context)
+
def execute(self, context):
- props = context.scene.muv_props.cpuv_selseq
- if not props.src_uvs or not props.src_pin_uvs:
+ props = context.scene.muv_props.copy_paste_uv_selseq
+ if not props.src_info:
self.report({'WARNING'}, "Need copy UV at first")
return {'CANCELLED'}
- if self.uv_map == "":
- self.report({'INFO'}, "Paste UV coordinate (selection sequence)")
- else:
- self.report(
- {'INFO'},
- "Paste UV coordinate (selection sequence) (UV map:%s)"
- % (self.uv_map))
-
obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
+ bm = common.create_bmesh(obj)
# get UV layer
- if self.uv_map == "":
- if not bm.loops.layers.uv:
- self.report(
- {'WARNING'}, "Object must have more than one UV map")
- return {'CANCELLED'}
- uv_layer = bm.loops.layers.uv.verify()
- else:
- uv_layer = bm.loops.layers.uv[self.uv_map]
+ uv_layers = impl.get_paste_uv_layers(self, obj, bm, props.src_info,
+ self.uv_map)
+ if not uv_layers:
+ return {'CANCELLED'}
# get selected face
- dest_uvs = []
- dest_pin_uvs = []
- dest_seams = []
- dest_face_indices = []
- for hist in bm.select_history:
- if isinstance(hist, bmesh.types.BMFace) and hist.select:
- dest_face_indices.append(hist.index)
- uvs = [l[uv_layer].uv.copy() for l in hist.loops]
- pin_uvs = [l[uv_layer].pin_uv for l in hist.loops]
- seams = [l.edge.seam for l in hist.loops]
- dest_uvs.append(uvs)
- dest_pin_uvs.append(pin_uvs)
- dest_seams.append(seams)
- if not dest_uvs or not dest_pin_uvs:
- self.report({'WARNING'}, "No faces are selected")
- return {'CANCELLED'}
- if self.strategy == 'N_N' and len(props.src_uvs) != len(dest_uvs):
- self.report(
- {'WARNING'},
- "Number of selected faces is different from copied faces " +
- "(src:%d, dest:%d)"
- % (len(props.src_uvs), len(dest_uvs)))
+ dest_info = impl.get_select_history_dest_face_info(self, bm, uv_layers,
+ props.src_info,
+ self.strategy)
+ if dest_info is None:
return {'CANCELLED'}
# paste
- for i, idx in enumerate(dest_face_indices):
- suv = None
- spuv = None
- ss = None
- duv = None
- if self.strategy == 'N_N':
- suv = props.src_uvs[i]
- spuv = props.src_pin_uvs[i]
- ss = props.src_seams[i]
- duv = dest_uvs[i]
- elif self.strategy == 'N_M':
- suv = props.src_uvs[i % len(props.src_uvs)]
- spuv = props.src_pin_uvs[i % len(props.src_pin_uvs)]
- ss = props.src_seams[i % len(props.src_seams)]
- duv = dest_uvs[i]
- if len(suv) != len(duv):
- self.report({'WARNING'}, "Some faces are different size")
- return {'CANCELLED'}
- suvs_fr = [uv for uv in suv]
- spuvs_fr = [pin_uv for pin_uv in spuv]
- ss_fr = [s for s in ss]
- # flip UVs
- if self.flip_copied_uv is True:
- suvs_fr.reverse()
- spuvs_fr.reverse()
- ss_fr.reverse()
- # rotate UVs
- for _ in range(self.rotate_copied_uv):
- uv = suvs_fr.pop()
- pin_uv = spuvs_fr.pop()
- s = ss_fr.pop()
- suvs_fr.insert(0, uv)
- spuvs_fr.insert(0, pin_uv)
- ss_fr.insert(0, s)
- # paste UVs
- for l, suv, spuv, ss in zip(bm.faces[idx].loops, suvs_fr,
- spuvs_fr, ss_fr):
- l[uv_layer].uv = suv
- l[uv_layer].pin_uv = spuv
- if self.copy_seams is True:
- l.edge.seam = ss
-
- self.report({'INFO'}, "%d face(s) are copied" % len(dest_uvs))
+ ret = impl.paste_uv(self, bm, props.src_info, dest_info, uv_layers,
+ self.strategy, self.flip_copied_uv,
+ self.rotate_copied_uv, self.copy_seams)
+ if ret:
+ return {'CANCELLED'}
+
+ face_count = len(props.src_info[list(dest_info.keys())[0]])
+ self.report({'INFO'}, "{} face(s) are pasted".format(face_count))
bmesh.update_edit_mesh(obj.data)
- if self.copy_seams is True:
- obj.data.show_edge_seams = True
return {'FINISHED'}
-class MUV_CPUVSelSeqPasteUVMenu(bpy.types.Menu):
+@BlClassRegistry()
+class MUV_MT_CopyPasteUV_SelSeqPasteUV(bpy.types.Menu):
"""
Menu class: Paste UV coordinate by selection sequence
"""
- bl_idname = "uv.muv_cpuv_selseq_paste_uv_menu"
- bl_label = "Paste UV (Selection Sequence)"
- bl_description = "Paste UV coordinate by selection sequence"
+ bl_idname = "uv.muv_copy_paste_uv_menu_selseq_paste_uv"
+ bl_label = "Paste UV (Selection Sequence) (Menu)"
+ bl_description = "Menu of Paste UV coordinate by selection sequence"
+
+ @classmethod
+ def poll(cls, context):
+ sc = context.scene
+ props = sc.muv_props.copy_paste_uv_selseq
+ if not props.src_uvs or not props.src_pin_uvs:
+ return False
+ return impl.is_valid_context(context)
def draw(self, context):
sc = context.scene
layout = self.layout
# create sub menu
obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
+ bm = common.create_bmesh(obj)
uv_maps = bm.loops.layers.uv.keys()
- ops = layout.operator(MUV_CPUVSelSeqPasteUV.bl_idname,
+
+ ops = layout.operator(MUV_OT_CopyPasteUV_SelSeqPasteUV.bl_idname,
text="[Default]")
- ops.uv_map = ""
- ops.copy_seams = sc.muv_cpuv_copy_seams
- ops.strategy = sc.muv_cpuv_strategy
+ ops.uv_map = "__default"
+ ops.copy_seams = sc.muv_copy_paste_uv_copy_seams
+ ops.strategy = sc.muv_copy_paste_uv_strategy
+
+ ops = layout.operator(MUV_OT_CopyPasteUV_SelSeqPasteUV.bl_idname,
+ text="[New]")
+ ops.uv_map = "__new"
+ ops.copy_seams = sc.muv_copy_paste_uv_copy_seams
+ ops.strategy = sc.muv_copy_paste_uv_strategy
+
+ ops = layout.operator(MUV_OT_CopyPasteUV_SelSeqPasteUV.bl_idname,
+ text="[All]")
+ ops.uv_map = "__all"
+ ops.copy_seams = sc.muv_copy_paste_uv_copy_seams
+ ops.strategy = sc.muv_copy_paste_uv_strategy
+
for m in uv_maps:
- ops = layout.operator(MUV_CPUVSelSeqPasteUV.bl_idname, text=m)
+ ops = layout.operator(MUV_OT_CopyPasteUV_SelSeqPasteUV.bl_idname,
+ text=m)
ops.uv_map = m
- ops.copy_seams = sc.muv_cpuv_copy_seams
- ops.strategy = sc.muv_cpuv_strategy
+ ops.copy_seams = sc.muv_copy_paste_uv_copy_seams
+ ops.strategy = sc.muv_copy_paste_uv_strategy