1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
import bpy, mathutils
bl_info = {
'name': 'Curve Remove Doubles',
'author': 'Michael Soluyanov',
'version': (1, 1),
'blender': (2, 80, 0),
'location': 'View3D > Context menu (W/RMB) > Remove Doubles',
'description': 'Adds comand "Remove Doubles" for curves',
'category': 'Object'
}
def main(context, distance = 0.01):
obj = context.active_object
dellist = []
if bpy.ops.object.mode_set.poll():
bpy.ops.object.mode_set(mode='EDIT')
for spline in obj.data.splines:
if len(spline.bezier_points) > 1:
for i in range(0, len(spline.bezier_points)):
if i == 0:
ii = len(spline.bezier_points) - 1
else:
ii = i - 1
dot = spline.bezier_points[i];
dot1 = spline.bezier_points[ii];
while dot1 in dellist and i != ii:
ii -= 1
if ii < 0:
ii = len(spline.bezier_points)-1
dot1 = spline.bezier_points[ii]
if dot.select_control_point and dot1.select_control_point and (i!=0 or spline.use_cyclic_u):
if (dot.co-dot1.co).length < distance:
# remove points and recreate hangles
dot1.handle_right_type = "FREE"
dot1.handle_right = dot.handle_right
dot1.co = (dot.co + dot1.co) / 2
dellist.append(dot)
else:
# Handles that are on main point position converts to vector,
# if next handle are also vector
if dot.handle_left_type == 'VECTOR' and (dot1.handle_right - dot1.co).length < distance:
dot1.handle_right_type = "VECTOR"
if dot1.handle_right_type == 'VECTOR' and (dot.handle_left - dot.co).length < distance:
dot.handle_left_type = "VECTOR"
bpy.ops.curve.select_all(action = 'DESELECT')
for dot in dellist:
dot.select_control_point = True
count = len(dellist)
bpy.ops.curve.delete(type = 'VERT')
bpy.ops.curve.select_all(action = 'SELECT')
return count
class CurveRemvDbs(bpy.types.Operator):
"""Merge consecutive points that are near to each other"""
bl_idname = 'curve.remove_doubles'
bl_label = 'Remove Doubles'
bl_options = {'REGISTER', 'UNDO'}
distance: bpy.props.FloatProperty(name = 'Distance', default = 0.01)
@classmethod
def poll(cls, context):
obj = context.active_object
return (obj and obj.type == 'CURVE')
def execute(self, context):
removed=main(context, self.distance)
self.report({'INFO'}, "Removed %d bezier points" % removed)
return {'FINISHED'}
def menu_func(self, context):
self.layout.operator(CurveRemvDbs.bl_idname, text='Remove Doubles')
def register():
bpy.utils.register_class(CurveRemvDbs)
bpy.types.VIEW3D_MT_edit_curve_context_menu.append(menu_func)
def unregister():
bpy.utils.unregister_class(CurveRemvDbs)
bpy.types.VIEW3D_MT_edit_curve_context_menu.remove(menu_func)
if __name__ == "__main__":
register()
|