5 'name': 'Curve Remove Doubles',
6 'author': 'Michael Soluyanov',
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
:
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
)):
30 ii
= len(spline
.bezier_points
) - 1
34 dot
= spline
.bezier_points
[i
];
35 dot1
= spline
.bezier_points
[ii
];
37 while dot1
in bezier_dellist
and i
!= ii
:
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
)
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"
60 if len(spline
.points
) > 1:
61 for i
in range(0, len(spline
.points
)):
64 ii
= len(spline
.points
) - 1
68 dot
= spline
.points
[i
];
69 dot1
= spline
.points
[ii
];
71 while dot1
in dellist
and i
!= ii
:
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
83 bpy
.ops
.curve
.select_all(action
= 'DESELECT')
85 for dot
in bezier_dellist
:
86 dot
.select_control_point
= True
91 bezier_count
= len(bezier_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)
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
)
121 def menu_func(self
, context
):
122 self
.layout
.operator(CurveRemvDbs
.bl_idname
, text
='Remove Doubles')
125 bpy
.utils
.register_class(CurveRemvDbs
)
126 bpy
.types
.VIEW3D_MT_edit_curve_context_menu
.append(menu_func
)
129 bpy
.utils
.unregister_class(CurveRemvDbs
)
130 bpy
.types
.VIEW3D_MT_edit_curve_context_menu
.remove(menu_func
)
132 if __name__
== "__main__":
135 operators
= [CurveRemvDbs
]