Import_3ds: Improved distance cue node setup
[blender-addons.git] / mesh_tools / mesh_vertex_chamfer.py
blobf42790b5a30a00c82e5c9953e9ac51822adf60ae
1 # SPDX-FileCopyrightText: 2019-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 bl_info = {
6 "name": "Vertex Chamfer",
7 "author": "Andrew Hale (TrumanBlending)",
8 "version": (0, 1),
9 "blender": (2, 63, 0),
10 "location": "Spacebar Menu",
11 "description": "Chamfer vertex",
12 "doc_url": "",
13 "category": "Mesh",
17 import bpy
18 import bmesh
19 from bpy.types import Operator
20 from bpy.props import (
21 BoolProperty,
22 FloatProperty,
26 class VertexChamfer(Operator):
27 bl_idname = "mesh.vertex_chamfer"
28 bl_label = "Chamfer Vertex"
29 bl_description = "Tri chamfer selected vertices"
30 bl_options = {'REGISTER', 'UNDO'}
32 factor: FloatProperty(
33 name="Factor",
34 description="Size of the Champfer",
35 default=0.1,
36 min=0.0,
37 soft_max=1.0
39 relative: BoolProperty(
40 name="Relative",
41 description="If Relative, Champfer size is relative to the edge length",
42 default=True
44 dissolve: BoolProperty(
45 name="Remove",
46 description="Remove/keep the original selected vertices\n"
47 "Remove creates a new triangle face between the Champfer edges,\n"
48 "similar to the Dissolve Vertices operator",
49 default=True
51 displace: FloatProperty(
52 name="Displace",
53 description="Active only if Remove option is disabled\n"
54 "Displaces the original selected vertices along the normals\n"
55 "defined by the Champfer edges",
56 soft_min=-5.0,
57 soft_max=5.0
60 @classmethod
61 def poll(self, context):
62 return (context.active_object.type == 'MESH' and
63 context.mode == 'EDIT_MESH')
65 def draw(self, context):
66 layout = self.layout
67 layout.prop(self, "factor", text="Distance" if self.relative else "Factor")
68 sub = layout.row()
69 sub.prop(self, "relative")
70 sub.prop(self, "dissolve")
71 if not self.dissolve:
72 layout.prop(self, "displace")
74 def execute(self, context):
75 ob = context.active_object
76 me = ob.data
77 bm = bmesh.from_edit_mesh(me)
79 bm.select_flush(True)
81 fac = self.factor
82 rel = self.relative
83 dissolve = self.dissolve
84 displace = self.displace
86 for v in bm.verts:
87 v.tag = False
89 # Loop over edges to find those with both verts selected
90 for e in bm.edges[:]:
91 e.tag = e.select
92 if not e.select:
93 continue
94 elen = e.calc_length()
95 val = fac if rel else fac / elen
96 val = min(val, 0.5)
97 # Loop over the verts of the edge to split
98 for v in e.verts:
99 # if val == 0.5 and e.other_vert(v).tag:
100 # continue
101 en, vn = bmesh.utils.edge_split(e, v, val)
102 en.tag = vn.tag = True
103 val = 1.0 if val == 1.0 else val / (1.0 - val)
105 # Get all verts which are selected but not created previously
106 verts = [v for v in bm.verts if v.select and not v.tag]
108 # Loop over all verts to split their linked edges
109 for v in verts:
110 for e in v.link_edges[:]:
111 if e.tag:
112 continue
113 elen = e.calc_length()
114 val = fac if rel else fac / elen
115 bmesh.utils.edge_split(e, v, val)
117 # Loop over all the loops of the vert
118 for l in v.link_loops:
119 # Split the face
120 bmesh.utils.face_split(
121 l.face,
122 l.link_loop_next.vert,
123 l.link_loop_prev.vert
126 # Remove the vert or displace otherwise
127 if dissolve:
128 bmesh.utils.vert_dissolve(v)
129 else:
130 v.co += displace * v.normal
132 me.calc_loop_triangles()
134 bpy.ops.object.mode_set(mode='OBJECT')
135 bpy.ops.object.mode_set(mode='EDIT')
137 return {'FINISHED'}
140 def register():
141 bpy.utils.register_class(VertexChamfer)
144 def unregister():
145 bpy.utils.unregister_class(VertexChamfer)
148 if __name__ == "__main__":
149 register()