diff options
Diffstat (limited to 'uv_magic_uv/op/copy_paste_uv_uvedit.py')
-rw-r--r-- | uv_magic_uv/op/copy_paste_uv_uvedit.py | 136 |
1 files changed, 119 insertions, 17 deletions
diff --git a/uv_magic_uv/op/copy_paste_uv_uvedit.py b/uv_magic_uv/op/copy_paste_uv_uvedit.py index 719687a6..16c0dfa5 100644 --- a/uv_magic_uv/op/copy_paste_uv_uvedit.py +++ b/uv_magic_uv/op/copy_paste_uv_uvedit.py @@ -24,21 +24,43 @@ __version__ = "5.2" __date__ = "17 Nov 2018" import bpy +import math +from math import atan2, sin, cos + +import bmesh +from mathutils import Vector + +from .. import common from ..utils.bl_class_registry import BlClassRegistry from ..utils.property_class_registry import PropertyClassRegistry -from ..impl import copy_paste_uv_uvedit_impl as impl -__all__ = [ - 'Properties', - 'MUV_OT_CopyPasteUVUVEdit_CopyUV', - 'MUV_OT_CopyPasteUVUVEdit_PasteUV', -] +def _is_valid_context(context): + obj = context.object + + # only edit mode is allowed to execute + if obj is None: + return False + if obj.type != 'MESH': + return False + 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 + for space in context.area.spaces: + if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'): + break + else: + return False + + return True @PropertyClassRegistry() -class Properties: +class _Properties: idname = "copy_paste_uv_uvedit" @classmethod @@ -64,15 +86,35 @@ class MUV_OT_CopyPasteUVUVEdit_CopyUV(bpy.types.Operator): bl_description = "Copy UV coordinate (only selected in UV/Image Editor)" bl_options = {'REGISTER', 'UNDO'} - def __init__(self): - self.__impl = impl.CopyUVImpl() - @classmethod def poll(cls, context): - return impl.CopyUVImpl.poll(context) + # we can not get area/space/region from console + if common.is_console_mode(): + return True + return _is_valid_context(context) def execute(self, context): - return self.__impl.execute(self, context) + props = context.scene.muv_props.copy_paste_uv_uvedit + 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() + + props.src_uvs = [] + 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'} @BlClassRegistry() @@ -86,12 +128,72 @@ class MUV_OT_CopyPasteUVUVEdit_PasteUV(bpy.types.Operator): bl_description = "Paste UV coordinate (only selected in UV/Image Editor)" bl_options = {'REGISTER', 'UNDO'} - def __init__(self): - self.__impl = impl.PasteUVImpl() - @classmethod def poll(cls, context): - return impl.PasteUVImpl.poll(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_uvedit + if not props.src_uvs: + return False + return _is_valid_context(context) def execute(self, context): - return self.__impl.execute(self, context) + props = context.scene.muv_props.copy_paste_uv_uvedit + 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'} |