CM3D2 Converter.misc_VIEW3D_MT_edit_mesh_merge

 1import numpy as np
 2import bpy
 3import bmesh
 4from . import common
 5from . import compat
 6
 7# メニュー等に項目追加
 8def menu_func(self, context):
 9    icon_id = common.kiss_icon()
10    self.layout.separator()
11    self.layout.label(text="CM3D2", icon_value=icon_id)
12    self.layout.operator('mesh.remove_and_mark_doubles')
13
14@compat.BlRegister()
15class CNV_OT_remove_and_mark_doubles(bpy.types.Operator):
16    bl_idname = 'mesh.remove_and_mark_doubles'
17    bl_label = "Remove and Mark Doubles"
18    bl_description = "Remove doubles while marking merged geometry as seams and/or sharp edges"
19    bl_options = {'REGISTER', 'UNDO'}
20
21    threshold           = bpy.props.FloatProperty(name="Merge Distance"    , default=0.0001, description="Maximum distance between elements to merge")
22    normal_threshold    = bpy.props.FloatProperty(name="Normal Angle"      , default=0.0000, description="Maximum angle between element's normals to mark sharp")
23    use_unselected      = bpy.props.BoolProperty(name="Unselected"         , default=False , description="Merge selected to other unselected vertices")
24    keep_custom_normals = bpy.props.BoolProperty(name="Keep Custom Normals", default=True  , description="Keep custom split normals")
25    mark_sharp          = bpy.props.BoolProperty(name="Mark Sharp"         , default=True  , description="Mark sharp")
26    
27    @classmethod
28    def poll(cls, context):
29        ob = context.active_object
30        return ob and ob.type == 'MESH' and ob.mode == 'EDIT'
31
32    def execute(self, context):
33        ob = context.active_object
34        me = ob.data
35        bm = bmesh.from_edit_mesh(me)
36
37        selected_verts = bm.verts if len(bm.select_history) <= 0 else set( filter(lambda v : v.select, bm.verts) )
38        search_verts   = bm.verts if self.use_unselected         else selected_verts  
39        
40        targetmap = bmesh.ops.find_doubles(bm, verts=search_verts, dist=self.threshold,
41            keep_verts=selected_verts if self.use_unselected else list())['targetmap']
42
43        selected_edges = bm.edges if len(bm.select_history) <= 0 else set( filter(lambda e : e.verts[0].select or e.verts[1].select, bm.edges) )
44        
45        # メッシュ整頓
46        if me.has_custom_normals:
47            layer = bm.loops.layers.float_vector.new('custom_normals.temp')
48            set_bmlayer_from_custom_normals(bm, layer, me)
49
50        if self.is_sharp:
51            pass
52        
53        # Remove Doubles
54        bmesh.ops.weld_verts(bm, targetmap=targetmap)
55        bmesh.update_edit_mesh(me)
56
57        if me.has_custom_normals:
58            if self.keep_custom_normals:
59                set_custom_normals_from_bmlayer(bm, layer, me)
60            bm.loops.layers.float_vector.remove(layer)
61            bmesh.update_edit_mesh(me)
62        
63        return {'FINISHED'}
64
65    @staticmethod
66    def set_bmlayer_from_custom_normals(bm, layer, me):
67        me.calc_normals_split()
68        for face in bm.faces:
69            for loop in face.loops:
70                loop[layer] = me.loops[loop.index].normal
71      
72    @staticmethod          
73    def set_custom_normals_from_bmlayer(bm, layer, me):
74        custom_normals = np.zeros((len(me.loops), 3))
75        for face in bm.faces:
76            for loop in face.loops:
77                custom_normals[loop.index] = loop[layer]
78        me.normals_split_custom_set(custom_normals)
@compat.BlRegister()
class CNV_OT_remove_and_mark_doubles(bpy_types.Operator):
15@compat.BlRegister()
16class CNV_OT_remove_and_mark_doubles(bpy.types.Operator):
17    bl_idname = 'mesh.remove_and_mark_doubles'
18    bl_label = "Remove and Mark Doubles"
19    bl_description = "Remove doubles while marking merged geometry as seams and/or sharp edges"
20    bl_options = {'REGISTER', 'UNDO'}
21
22    threshold           = bpy.props.FloatProperty(name="Merge Distance"    , default=0.0001, description="Maximum distance between elements to merge")
23    normal_threshold    = bpy.props.FloatProperty(name="Normal Angle"      , default=0.0000, description="Maximum angle between element's normals to mark sharp")
24    use_unselected      = bpy.props.BoolProperty(name="Unselected"         , default=False , description="Merge selected to other unselected vertices")
25    keep_custom_normals = bpy.props.BoolProperty(name="Keep Custom Normals", default=True  , description="Keep custom split normals")
26    mark_sharp          = bpy.props.BoolProperty(name="Mark Sharp"         , default=True  , description="Mark sharp")
27    
28    @classmethod
29    def poll(cls, context):
30        ob = context.active_object
31        return ob and ob.type == 'MESH' and ob.mode == 'EDIT'
32
33    def execute(self, context):
34        ob = context.active_object
35        me = ob.data
36        bm = bmesh.from_edit_mesh(me)
37
38        selected_verts = bm.verts if len(bm.select_history) <= 0 else set( filter(lambda v : v.select, bm.verts) )
39        search_verts   = bm.verts if self.use_unselected         else selected_verts  
40        
41        targetmap = bmesh.ops.find_doubles(bm, verts=search_verts, dist=self.threshold,
42            keep_verts=selected_verts if self.use_unselected else list())['targetmap']
43
44        selected_edges = bm.edges if len(bm.select_history) <= 0 else set( filter(lambda e : e.verts[0].select or e.verts[1].select, bm.edges) )
45        
46        # メッシュ整頓
47        if me.has_custom_normals:
48            layer = bm.loops.layers.float_vector.new('custom_normals.temp')
49            set_bmlayer_from_custom_normals(bm, layer, me)
50
51        if self.is_sharp:
52            pass
53        
54        # Remove Doubles
55        bmesh.ops.weld_verts(bm, targetmap=targetmap)
56        bmesh.update_edit_mesh(me)
57
58        if me.has_custom_normals:
59            if self.keep_custom_normals:
60                set_custom_normals_from_bmlayer(bm, layer, me)
61            bm.loops.layers.float_vector.remove(layer)
62            bmesh.update_edit_mesh(me)
63        
64        return {'FINISHED'}
65
66    @staticmethod
67    def set_bmlayer_from_custom_normals(bm, layer, me):
68        me.calc_normals_split()
69        for face in bm.faces:
70            for loop in face.loops:
71                loop[layer] = me.loops[loop.index].normal
72      
73    @staticmethod          
74    def set_custom_normals_from_bmlayer(bm, layer, me):
75        custom_normals = np.zeros((len(me.loops), 3))
76        for face in bm.faces:
77            for loop in face.loops:
78                custom_normals[loop.index] = loop[layer]
79        me.normals_split_custom_set(custom_normals)
bl_idname = 'mesh.remove_and_mark_doubles'
bl_label = 'Remove and Mark Doubles'
bl_description = 'Remove doubles while marking merged geometry as seams and/or sharp edges'
bl_options = {'REGISTER', 'UNDO'}
threshold: <_PropertyDeferred, <built-in function FloatProperty>, {'name': 'Merge Distance', 'default': 0.0001, 'description': 'Maximum distance between elements to merge', 'attr': 'threshold'}> = <_PropertyDeferred, <built-in function FloatProperty>, {'name': 'Merge Distance', 'default': 0.0001, 'description': 'Maximum distance between elements to merge', 'attr': 'threshold'}>
normal_threshold: <_PropertyDeferred, <built-in function FloatProperty>, {'name': 'Normal Angle', 'default': 0.0, 'description': "Maximum angle between element's normals to mark sharp", 'attr': 'normal_threshold'}> = <_PropertyDeferred, <built-in function FloatProperty>, {'name': 'Normal Angle', 'default': 0.0, 'description': "Maximum angle between element's normals to mark sharp", 'attr': 'normal_threshold'}>
use_unselected: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Unselected', 'default': False, 'description': 'Merge selected to other unselected vertices', 'attr': 'use_unselected'}> = <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Unselected', 'default': False, 'description': 'Merge selected to other unselected vertices', 'attr': 'use_unselected'}>
keep_custom_normals: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Keep Custom Normals', 'default': True, 'description': 'Keep custom split normals', 'attr': 'keep_custom_normals'}> = <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Keep Custom Normals', 'default': True, 'description': 'Keep custom split normals', 'attr': 'keep_custom_normals'}>
mark_sharp: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Mark Sharp', 'default': True, 'description': 'Mark sharp', 'attr': 'mark_sharp'}> = <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Mark Sharp', 'default': True, 'description': 'Mark sharp', 'attr': 'mark_sharp'}>
@classmethod
def poll(cls, context):
28    @classmethod
29    def poll(cls, context):
30        ob = context.active_object
31        return ob and ob.type == 'MESH' and ob.mode == 'EDIT'
def execute(self, context):
33    def execute(self, context):
34        ob = context.active_object
35        me = ob.data
36        bm = bmesh.from_edit_mesh(me)
37
38        selected_verts = bm.verts if len(bm.select_history) <= 0 else set( filter(lambda v : v.select, bm.verts) )
39        search_verts   = bm.verts if self.use_unselected         else selected_verts  
40        
41        targetmap = bmesh.ops.find_doubles(bm, verts=search_verts, dist=self.threshold,
42            keep_verts=selected_verts if self.use_unselected else list())['targetmap']
43
44        selected_edges = bm.edges if len(bm.select_history) <= 0 else set( filter(lambda e : e.verts[0].select or e.verts[1].select, bm.edges) )
45        
46        # メッシュ整頓
47        if me.has_custom_normals:
48            layer = bm.loops.layers.float_vector.new('custom_normals.temp')
49            set_bmlayer_from_custom_normals(bm, layer, me)
50
51        if self.is_sharp:
52            pass
53        
54        # Remove Doubles
55        bmesh.ops.weld_verts(bm, targetmap=targetmap)
56        bmesh.update_edit_mesh(me)
57
58        if me.has_custom_normals:
59            if self.keep_custom_normals:
60                set_custom_normals_from_bmlayer(bm, layer, me)
61            bm.loops.layers.float_vector.remove(layer)
62            bmesh.update_edit_mesh(me)
63        
64        return {'FINISHED'}
@staticmethod
def set_bmlayer_from_custom_normals(bm, layer, me):
66    @staticmethod
67    def set_bmlayer_from_custom_normals(bm, layer, me):
68        me.calc_normals_split()
69        for face in bm.faces:
70            for loop in face.loops:
71                loop[layer] = me.loops[loop.index].normal
@staticmethod
def set_custom_normals_from_bmlayer(bm, layer, me):
73    @staticmethod          
74    def set_custom_normals_from_bmlayer(bm, layer, me):
75        custom_normals = np.zeros((len(me.loops), 3))
76        for face in bm.faces:
77            for loop in face.loops:
78                custom_normals[loop.index] = loop[layer]
79        me.normals_split_custom_set(custom_normals)
bl_rna = <bpy_struct, Struct("MESH_OT_remove_and_mark_doubles")>
Inherited Members
bpy_types.Operator
as_keywords
poll_message_set
builtins.bpy_struct
keys
values
items
get
pop
as_pointer
keyframe_insert
keyframe_delete
driver_add
driver_remove
is_property_set
property_unset
is_property_hidden
is_property_readonly
is_property_overridable_library
property_overridable_library_set
path_resolve
path_from_id
type_recast
bl_rna_get_subclass_py
bl_rna_get_subclass
id_properties_ensure
id_properties_clear
id_properties_ui
id_data