Addon: Curve Tools: Made changes from Lichtso github

This commit is contained in:
Vladimir Spivak 2021-01-07 19:05:54 +02:00
parent cef282cc9a
commit d2f6cf924a
4 changed files with 56 additions and 58 deletions

View File

@ -25,11 +25,10 @@ bl_info = {
"name": "Curve Tools",
"description": "Adds some functionality for bezier/nurbs curve/surface modeling",
"author": "Mackraken",
"version": (0, 4, 4),
"version": (0, 4, 5),
"blender": (2, 80, 0),
"location": "View3D > Tool Shelf > Edit Tab",
"warning": "WIP",
"doc_url": "",
"doc_url": "{BLENDER_MANUAL_URL}/addons/add_curve/curve_tools.html",
"category": "Add Curve",
}

View File

@ -72,7 +72,6 @@ class Boolean(bpy.types.Operator):
current_mode = bpy.context.object.mode
bpy.ops.object.mode_set(mode = 'EDIT')
if bpy.context.object.data.dimensions != '2D':
self.report({'WARNING'}, 'Can only be applied in 2D')
return {'CANCELLED'}
@ -116,7 +115,7 @@ class HandleProjection(bpy.types.Operator):
@classmethod
def poll(cls, context):
return internal.curveObject()
return util.Selected1OrMoreCurves()
def execute(self, context):
segments = internal.bezierSegments(bpy.context.object.data.splines, True)
@ -132,54 +131,34 @@ class MergeEnds(bpy.types.Operator):
bl_description = bl_label = 'Merge Ends'
bl_options = {'REGISTER', 'UNDO'}
max_dist: bpy.props.FloatProperty(name='Distance', description='Threshold of the maximum distance at which two control points are merged', unit='LENGTH', min=0.0, default=0.1)
@classmethod
def poll(cls, context):
return util.Selected1OrMoreCurves()
def execute(self, context):
points = []
selected_splines = []
is_last_point = []
for spline in bpy.context.object.data.splines:
if spline.type != 'BEZIER' or spline.use_cyclic_u:
splines = [spline for spline in internal.getSelectedSplines(True, False) if spline.use_cyclic_u == False]
while len(splines) > 0:
spline = splines.pop()
closest_pair = ([spline, spline], [spline.bezier_points[0], spline.bezier_points[-1]], [False, True])
min_dist = (spline.bezier_points[0].co-spline.bezier_points[-1].co).length
for other_spline in splines:
for j in range(-1, 1):
for i in range(-1, 1):
dist = (spline.bezier_points[i].co-other_spline.bezier_points[j].co).length
if min_dist > dist:
min_dist = dist
closest_pair = ([spline, other_spline], [spline.bezier_points[i], other_spline.bezier_points[j]], [i == -1, j == -1])
if min_dist > self.max_dist:
continue
if spline.bezier_points[0].select_control_point:
points.append(spline.bezier_points[0])
selected_splines.append(spline)
is_last_point.append(False)
if spline.bezier_points[-1].select_control_point:
points.append(spline.bezier_points[-1])
selected_splines.append(spline)
is_last_point.append(True)
if closest_pair[0][0] != closest_pair[0][1]:
splines.remove(closest_pair[0][1])
spline = internal.mergeEnds(closest_pair[0], closest_pair[1], closest_pair[2])
if spline.use_cyclic_u == False:
splines.append(spline)
if len(points) != 2:
self.report({'WARNING'}, 'Invalid selection')
return {'CANCELLED'}
if is_last_point[0]:
points[1], points[0] = points[0], points[1]
selected_splines[1], selected_splines[0] = selected_splines[0], selected_splines[1]
is_last_point[1], is_last_point[0] = is_last_point[0], is_last_point[1]
points[0].handle_left_type = 'FREE'
points[0].handle_right_type = 'FREE'
new_co = (points[0].co+points[1].co)*0.5
handle = (points[1].handle_left if is_last_point[1] else points[1].handle_right)+new_co-points[1].co
if is_last_point[0]:
points[0].handle_left += new_co-points[0].co
points[0].handle_right = handle
else:
points[0].handle_right += new_co-points[0].co
points[0].handle_left = handle
points[0].co = new_co
point_index = 0 if selected_splines[0] == selected_splines[1] else len(selected_splines[1].bezier_points)
bpy.ops.curve.make_segment()
point = selected_splines[0].bezier_points[point_index]
point.select_control_point = False
point.select_left_handle = False
point.select_right_handle = False
bpy.ops.curve.delete()
return {'FINISHED'}
class Subdivide(bpy.types.Operator):
@ -219,7 +198,7 @@ class Array(bpy.types.Operator):
bl_description = bl_label = 'Array'
bl_options = {'REGISTER', 'UNDO'}
offset: bpy.props.FloatVectorProperty(name='Offset', unit='LENGTH', description='Vector between to copies', subtype='DIRECTION', default=(1.0, 0.0, 0.0), size=3)
offset: bpy.props.FloatVectorProperty(name='Offset', unit='LENGTH', description='Vector between to copies', subtype='DIRECTION', default=(0.0, 0.0, -1.0), size=3)
count: bpy.props.IntProperty(name='Count', description='Number of copies', min=1, default=2)
connect: bpy.props.BoolProperty(name='Connect', description='Concatenate individual copies', default=False)
serpentine: bpy.props.BoolProperty(name='Serpentine', description='Switch direction of every second copy', default=False)

View File

@ -637,6 +637,27 @@ def addBezierSpline(obj, cyclic, vertices, weights=None, select=False):
point.handle_left_type = 'VECTOR'
return spline
def mergeEnds(splines, points, is_last_point):
bpy.ops.curve.select_all(action='DESELECT')
points[0].handle_left_type = points[0].handle_right_type = 'FREE'
new_co = (points[0].co+points[1].co)*0.5
handle = (points[1].handle_left if is_last_point[1] else points[1].handle_right)+new_co-points[1].co
points[0].select_left_handle = points[0].select_right_handle = True
if is_last_point[0]:
points[0].handle_left += new_co-points[0].co
points[0].handle_right = handle
else:
points[0].handle_right += new_co-points[0].co
points[0].handle_left = handle
points[0].co = new_co
points[0].select_control_point = points[1].select_control_point = True
bpy.ops.curve.make_segment()
spline = splines[0] if splines[0] in bpy.context.object.data.splines.values() else splines[1]
point = next(point for point in spline.bezier_points if point.select_left_handle)
point.select_left_handle = point.select_right_handle = point.select_control_point = False
bpy.ops.curve.delete()
return spline
def polygonArcAt(center, radius, begin_angle, angle, step_angle, include_ends):
vertices = []
circle_samples = math.ceil(abs(angle)/step_angle)
@ -807,7 +828,6 @@ def dogBone(spline, radius):
vertices.append([next_segment_points[0], corner, next_segment_points[0]])
vertices.append([corner, next_segment_points[0], next_segment_points[3]])
iterateSpline(spline, handlePoint)
print(vertices)
return vertices
def discretizeCurve(spline, step_angle, samples):

View File

@ -113,7 +113,14 @@ class SliceMesh(bpy.types.Operator):
self.offset = 0.0
self.slice_count = 3
self.mode = 'PITCH'
self.execute(context)
self.input_obj = bpy.context.object
depsgraph = context.evaluated_depsgraph_get()
self.mesh = bmesh.new()
self.mesh.from_object(self.input_obj, depsgraph, deform=True, cage=False, face_normals=True)
self.mesh.transform(bpy.context.scene.cursor.matrix.inverted()@self.input_obj.matrix_world)
self.result = internal.addObject('CURVE', 'Slices')
self.result.matrix_world = bpy.context.scene.cursor.matrix
self.perform(context)
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
@ -148,9 +155,12 @@ class SliceMesh(bpy.types.Operator):
self.mode = 'OFFSET'
return {'RUNNING_MODAL'}
elif self.mode == 'OFFSET':
self.mesh.free()
return {'FINISHED'}
elif event.type in {'RIGHTMOUSE', 'ESC'}:
self.mesh.free()
bpy.context.scene.collection.objects.unlink(self.result)
bpy.context.view_layer.objects.active = self.input_obj
return {'CANCELLED'}
else:
return {'PASS_THROUGH'}
@ -158,16 +168,6 @@ class SliceMesh(bpy.types.Operator):
self.perform(context)
return {'RUNNING_MODAL'}
def execute(self, context):
depsgraph = context.evaluated_depsgraph_get()
self.mesh = bmesh.new()
self.mesh.from_object(bpy.context.object, depsgraph, deform=True, cage=False, face_normals=True)
self.mesh.transform(bpy.context.scene.cursor.matrix.inverted()@bpy.context.object.matrix_world)
self.result = internal.addObject('CURVE', 'Slices')
self.result.matrix_world = bpy.context.scene.cursor.matrix
self.perform(context)
return {'FINISHED'}
class DogBone(bpy.types.Operator):
bl_idname = 'curvetools.add_toolpath_dogbone'
bl_description = bl_label = 'Dog Bone'