Addon: Curve Tools: Made changes from Lichtso github
This commit is contained in:
parent
cef282cc9a
commit
d2f6cf924a
|
@ -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",
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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'
|
||||
|
|
Loading…
Reference in New Issue