1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
22 "name": "Vertex Chamfer",
23 "author": "Andrew Hale (TrumanBlending)",
25 "blender": (2, 63, 0),
26 "location": "Spacebar Menu",
27 "description": "Chamfer vertex",
34 from bpy
.types
import Operator
35 from bpy
.props
import (
41 class VertexChamfer(Operator
):
42 bl_idname
= "mesh.vertex_chamfer"
43 bl_label
= "Chamfer Vertex"
44 bl_description
= "Tri chamfer selected vertices"
45 bl_options
= {'REGISTER', 'UNDO'}
47 factor
= FloatProperty(
49 description
="Size of the Champfer",
54 relative
= BoolProperty(
56 description
="If Relative, Champfer size is relative to the edge length",
59 dissolve
= BoolProperty(
61 description
="Remove/keep the original selected vertices\n"
62 "Remove creates a new triangle face between the Champfer edges,\n"
63 "similar to the Dissolve Vertices operator",
66 displace
= FloatProperty(
68 description
="Active only if Remove option is disabled\n"
69 "Displaces the original selected vertices along the normals\n"
70 "defined by the Champfer edges",
76 def poll(self
, context
):
77 return (context
.active_object
.type == 'MESH' and
78 context
.mode
== 'EDIT_MESH')
80 def draw(self
, context
):
82 layout
.prop(self
, "factor", text
="Distance" if self
.relative
else "Factor")
84 sub
.prop(self
, "relative")
85 sub
.prop(self
, "dissolve")
87 layout
.prop(self
, "displace")
89 def execute(self
, context
):
90 ob
= context
.active_object
92 bm
= bmesh
.from_edit_mesh(me
)
98 dissolve
= self
.dissolve
99 displace
= self
.displace
104 # Loop over edges to find those with both verts selected
105 for e
in bm
.edges
[:]:
109 elen
= e
.calc_length()
110 val
= fac
if rel
else fac
/ elen
112 # Loop over the verts of the edge to split
114 # if val == 0.5 and e.other_vert(v).tag:
116 en
, vn
= bmesh
.utils
.edge_split(e
, v
, val
)
117 en
.tag
= vn
.tag
= True
118 val
= 1.0 if val
== 1.0 else val
/ (1.0 - val
)
120 # Get all verts which are selected but not created previously
121 verts
= [v
for v
in bm
.verts
if v
.select
and not v
.tag
]
123 # Loop over all verts to split their linked edges
125 for e
in v
.link_edges
[:]:
128 elen
= e
.calc_length()
129 val
= fac
if rel
else fac
/ elen
130 bmesh
.utils
.edge_split(e
, v
, val
)
132 # Loop over all the loops of the vert
133 for l
in v
.link_loops
:
135 bmesh
.utils
.face_split(
137 l
.link_loop_next
.vert
,
138 l
.link_loop_prev
.vert
141 # Remove the vert or displace otherwise
143 bmesh
.utils
.vert_dissolve(v
)
145 v
.co
+= displace
* v
.normal
147 me
.calc_loop_triangles()
153 bpy
.utils
.register_class(VertexChamfer
)
157 bpy
.utils
.unregister_class(VertexChamfer
)
160 if __name__
== "__main__":