Merge branch 'blender-v2.92-release'
[blender-addons.git] / curve_tools / remove_doubles.py
blobd69b3e0aff384534bb0b2a201cdea4507474944e
1 import bpy, mathutils
2 from . import util
4 bl_info = {
5 'name': 'Curve Remove Doubles',
6 'author': 'Michael Soluyanov',
7 'version': (1, 1),
8 'blender': (2, 80, 0),
9 'location': 'View3D > Context menu (W/RMB) > Remove Doubles',
10 'description': 'Adds comand "Remove Doubles" for curves',
11 'category': 'Add Curve'
14 def main(context, distance = 0.01):
16 selected_Curves = util.GetSelectedCurves()
17 if bpy.ops.object.mode_set.poll():
18 bpy.ops.object.mode_set(mode='EDIT')
20 for curve in selected_Curves:
21 bezier_dellist = []
22 dellist = []
24 for spline in curve.data.splines:
25 if spline.type == 'BEZIER':
26 if len(spline.bezier_points) > 1:
27 for i in range(0, len(spline.bezier_points)):
29 if i == 0:
30 ii = len(spline.bezier_points) - 1
31 else:
32 ii = i - 1
34 dot = spline.bezier_points[i];
35 dot1 = spline.bezier_points[ii];
37 while dot1 in bezier_dellist and i != ii:
38 ii -= 1
39 if ii < 0:
40 ii = len(spline.bezier_points)-1
41 dot1 = spline.bezier_points[ii]
43 if dot.select_control_point and dot1.select_control_point and (i!=0 or spline.use_cyclic_u):
45 if (dot.co-dot1.co).length < distance:
46 # remove points and recreate hangles
47 dot1.handle_right_type = "FREE"
48 dot1.handle_right = dot.handle_right
49 dot1.co = (dot.co + dot1.co) / 2
50 bezier_dellist.append(dot)
52 else:
53 # Handles that are on main point position converts to vector,
54 # if next handle are also vector
55 if dot.handle_left_type == 'VECTOR' and (dot1.handle_right - dot1.co).length < distance:
56 dot1.handle_right_type = "VECTOR"
57 if dot1.handle_right_type == 'VECTOR' and (dot.handle_left - dot.co).length < distance:
58 dot.handle_left_type = "VECTOR"
59 else:
60 if len(spline.points) > 1:
61 for i in range(0, len(spline.points)):
63 if i == 0:
64 ii = len(spline.points) - 1
65 else:
66 ii = i - 1
68 dot = spline.points[i];
69 dot1 = spline.points[ii];
71 while dot1 in dellist and i != ii:
72 ii -= 1
73 if ii < 0:
74 ii = len(spline.points)-1
75 dot1 = spline.points[ii]
77 if dot.select and dot1.select and (i!=0 or spline.use_cyclic_u):
79 if (dot.co-dot1.co).length < distance:
80 dot1.co = (dot.co + dot1.co) / 2
81 dellist.append(dot)
83 bpy.ops.curve.select_all(action = 'DESELECT')
85 for dot in bezier_dellist:
86 dot.select_control_point = True
88 for dot in dellist:
89 dot.select = True
91 bezier_count = len(bezier_dellist)
92 count = len(dellist)
94 bpy.ops.curve.delete(type = 'VERT')
96 bpy.ops.curve.select_all(action = 'DESELECT')
98 return bezier_count + count
102 class CurveRemvDbs(bpy.types.Operator):
103 """Merge consecutive points that are near to each other"""
104 bl_idname = 'curvetools.remove_doubles'
105 bl_label = 'Remove Doubles'
106 bl_options = {'REGISTER', 'UNDO'}
108 distance: bpy.props.FloatProperty(name = 'Distance', default = 0.01)
110 @classmethod
111 def poll(cls, context):
112 return util.Selected1OrMoreCurves()
114 def execute(self, context):
115 removed=main(context, self.distance)
116 self.report({'INFO'}, "Removed %d bezier points" % removed)
117 return {'FINISHED'}
121 def menu_func(self, context):
122 self.layout.operator(CurveRemvDbs.bl_idname, text='Remove Doubles')
124 def register():
125 bpy.utils.register_class(CurveRemvDbs)
126 bpy.types.VIEW3D_MT_edit_curve_context_menu.append(menu_func)
128 def unregister():
129 bpy.utils.unregister_class(CurveRemvDbs)
130 bpy.types.VIEW3D_MT_edit_curve_context_menu.remove(menu_func)
132 if __name__ == "__main__":
133 register()
135 operators = [CurveRemvDbs]