Curve Tools: many bugs fixed
This commit is contained in:
parent
3c31740565
commit
f31572ecd2
|
@ -17,7 +17,7 @@ from . import Math
|
|||
# 1 CURVE SELECTED
|
||||
# ################
|
||||
class OperatorCurveInfo(bpy.types.Operator):
|
||||
bl_idname = "curvetools2.operatorcurveinfo"
|
||||
bl_idname = "curvetools.operatorcurveinfo"
|
||||
bl_label = "Info"
|
||||
bl_description = "Displays general info about the active/selected curve"
|
||||
|
||||
|
@ -45,7 +45,7 @@ class OperatorCurveInfo(bpy.types.Operator):
|
|||
|
||||
|
||||
class OperatorCurveLength(bpy.types.Operator):
|
||||
bl_idname = "curvetools2.operatorcurvelength"
|
||||
bl_idname = "curvetools.operatorcurvelength"
|
||||
bl_label = "Length"
|
||||
bl_description = "Calculates the length of the active/selected curve"
|
||||
|
||||
|
@ -65,7 +65,7 @@ class OperatorCurveLength(bpy.types.Operator):
|
|||
|
||||
|
||||
class OperatorSplinesInfo(bpy.types.Operator):
|
||||
bl_idname = "curvetools2.operatorsplinesinfo"
|
||||
bl_idname = "curvetools.operatorsplinesinfo"
|
||||
bl_label = "Info"
|
||||
bl_description = "Displays general info about the splines of the active/selected curve"
|
||||
|
||||
|
@ -98,7 +98,7 @@ class OperatorSplinesInfo(bpy.types.Operator):
|
|||
|
||||
|
||||
class OperatorSegmentsInfo(bpy.types.Operator):
|
||||
bl_idname = "curvetools2.operatorsegmentsinfo"
|
||||
bl_idname = "curvetools.operatorsegmentsinfo"
|
||||
bl_label = "Info"
|
||||
bl_description = "Displays general info about the segments of the active/selected curve"
|
||||
|
||||
|
@ -139,7 +139,7 @@ class OperatorSegmentsInfo(bpy.types.Operator):
|
|||
|
||||
|
||||
class OperatorOriginToSpline0Start(bpy.types.Operator):
|
||||
bl_idname = "curvetools2.operatororigintospline0start"
|
||||
bl_idname = "curvetools.operatororigintospline0start"
|
||||
bl_label = "OriginToSpline0Start"
|
||||
bl_description = "Sets the origin of the active/selected curve to the starting point of the (first) spline. Nice for curve modifiers."
|
||||
|
||||
|
@ -150,19 +150,24 @@ class OperatorOriginToSpline0Start(bpy.types.Operator):
|
|||
|
||||
|
||||
def execute(self, context):
|
||||
|
||||
|
||||
blCurve = context.active_object
|
||||
blSpline = blCurve.data.splines[0]
|
||||
newOrigin = blCurve.matrix_world @ blSpline.bezier_points[0].co
|
||||
|
||||
origOrigin = bpy.context.scene.cursor.location.copy()
|
||||
print("--", "origOrigin: %.6f, %.6f, %.6f" % (origOrigin.x, origOrigin.y, origOrigin.z))
|
||||
print("--", "newOrigin: %.6f, %.6f, %.6f" % (newOrigin.x, newOrigin.y, newOrigin.z))
|
||||
self.report({'INFO'}, "origOrigin: %.6f, %.6f, %.6f" % (origOrigin.x, origOrigin.y, origOrigin.z))
|
||||
self.report({'INFO'}, "newOrigin: %.6f, %.6f, %.6f" % (newOrigin.x, newOrigin.y, newOrigin.z))
|
||||
|
||||
current_mode = bpy.context.object.mode
|
||||
|
||||
bpy.ops.object.mode_set(mode = 'OBJECT')
|
||||
bpy.context.scene.cursor.location = newOrigin
|
||||
bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
|
||||
bpy.context.scene.cursor.location = origOrigin
|
||||
|
||||
self.report({'INFO'}, "TODO: OperatorOriginToSpline0Start")
|
||||
|
||||
bpy.ops.object.mode_set (mode = current_mode)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
@ -171,7 +176,7 @@ class OperatorOriginToSpline0Start(bpy.types.Operator):
|
|||
# 2 CURVES SELECTED
|
||||
# #################
|
||||
class OperatorIntersectCurves(bpy.types.Operator):
|
||||
bl_idname = "curvetools2.operatorintersectcurves"
|
||||
bl_idname = "curvetools.operatorintersectcurves"
|
||||
bl_label = "Intersect"
|
||||
bl_description = "Intersects selected curves"
|
||||
|
||||
|
@ -218,9 +223,11 @@ class OperatorIntersectCurves(bpy.types.Operator):
|
|||
|
||||
return {'FINISHED'}
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# OperatorLoftCurves
|
||||
|
||||
class OperatorLoftCurves(bpy.types.Operator):
|
||||
bl_idname = "curvetools2.operatorloftcurves"
|
||||
bl_idname = "curvetools.operatorloftcurves"
|
||||
bl_label = "Loft"
|
||||
bl_description = "Lofts selected curves"
|
||||
|
||||
|
@ -241,9 +248,11 @@ class OperatorLoftCurves(bpy.types.Operator):
|
|||
return {'FINISHED'}
|
||||
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# OperatorSweepCurves
|
||||
|
||||
class OperatorSweepCurves(bpy.types.Operator):
|
||||
bl_idname = "curvetools2.operatorsweepcurves"
|
||||
bl_idname = "curvetools.operatorsweepcurves"
|
||||
bl_label = "Sweep"
|
||||
bl_description = "Sweeps the active curve along to other curve (rail)"
|
||||
|
||||
|
@ -268,7 +277,7 @@ class OperatorSweepCurves(bpy.types.Operator):
|
|||
# 3 CURVES SELECTED
|
||||
# #################
|
||||
class OperatorBirail(bpy.types.Operator):
|
||||
bl_idname = "curvetools2.operatorbirail"
|
||||
bl_idname = "curvetools.operatorbirail"
|
||||
bl_label = "Birail"
|
||||
bl_description = "Generates a birailed surface from 3 selected curves -- in order: rail1, rail2 and profile"
|
||||
|
||||
|
@ -291,7 +300,7 @@ class OperatorBirail(bpy.types.Operator):
|
|||
# 1 OR MORE CURVES SELECTED
|
||||
# #########################
|
||||
class OperatorSplinesSetResolution(bpy.types.Operator):
|
||||
bl_idname = "curvetools2.operatorsplinessetresolution"
|
||||
bl_idname = "curvetools.operatorsplinessetresolution"
|
||||
bl_label = "SplinesSetResolution"
|
||||
bl_description = "Sets the resolution of all splines"
|
||||
|
||||
|
@ -311,10 +320,11 @@ class OperatorSplinesSetResolution(bpy.types.Operator):
|
|||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# OperatorSplinesRemoveZeroSegment
|
||||
|
||||
class OperatorSplinesRemoveZeroSegment(bpy.types.Operator):
|
||||
bl_idname = "curvetools2.operatorsplinesremovezerosegment"
|
||||
bl_idname = "curvetools.operatorsplinesremovezerosegment"
|
||||
bl_label = "SplinesRemoveZeroSegment"
|
||||
bl_description = "Removes splines with no segments -- they seem to creep up, sometimes.."
|
||||
|
||||
|
@ -344,10 +354,11 @@ class OperatorSplinesRemoveZeroSegment(bpy.types.Operator):
|
|||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# OperatorSplinesRemoveShort
|
||||
|
||||
class OperatorSplinesRemoveShort(bpy.types.Operator):
|
||||
bl_idname = "curvetools2.operatorsplinesremoveshort"
|
||||
bl_idname = "curvetools.operatorsplinesremoveshort"
|
||||
bl_label = "SplinesRemoveShort"
|
||||
bl_description = "Removes splines with a length smaller than the threshold"
|
||||
|
||||
|
@ -372,10 +383,11 @@ class OperatorSplinesRemoveShort(bpy.types.Operator):
|
|||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# OperatorSplinesJoinNeighbouring
|
||||
|
||||
class OperatorSplinesJoinNeighbouring(bpy.types.Operator):
|
||||
bl_idname = "curvetools2.operatorsplinesjoinneighbouring"
|
||||
bl_idname = "curvetools.operatorsplinesjoinneighbouring"
|
||||
bl_label = "SplinesJoinNeighbouring"
|
||||
bl_description = "Joins neighbouring splines within a distance smaller than the threshold"
|
||||
|
||||
|
@ -403,6 +415,9 @@ class OperatorSplinesJoinNeighbouring(bpy.types.Operator):
|
|||
|
||||
return {'FINISHED'}
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# SurfaceFromBezier
|
||||
|
||||
def SurfaceFromBezier(surfacedata, points, center):
|
||||
|
||||
len_points = len(points) - 1
|
||||
|
@ -524,8 +539,11 @@ def SurfaceFromBezier(surfacedata, points, center):
|
|||
for p in s.points:
|
||||
p.select = False
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Convert selected faces to Bezier
|
||||
|
||||
class ConvertSelectedFacesToBezier(bpy.types.Operator):
|
||||
bl_idname = "curvetools2.convert_selected_face_to_bezier"
|
||||
bl_idname = "curvetools.convert_selected_face_to_bezier"
|
||||
bl_label = "Convert selected faces to Bezier"
|
||||
bl_description = "Convert selected faces to Bezier"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
@ -560,8 +578,11 @@ class ConvertSelectedFacesToBezier(bpy.types.Operator):
|
|||
|
||||
return {'FINISHED'}
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Convert Bezier to Surface
|
||||
|
||||
class ConvertBezierToSurface(bpy.types.Operator):
|
||||
bl_idname = "curvetools2.convert_bezier_to_surface"
|
||||
bl_idname = "curvetools.convert_bezier_to_surface"
|
||||
bl_label = "Convert Bezier to Surface"
|
||||
bl_description = "Convert Bezier to Surface"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
@ -632,3 +653,293 @@ class ConvertBezierToSurface(bpy.types.Operator):
|
|||
surfacedata.resolution_v = self.Resolution_V
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Fillet
|
||||
|
||||
class BezierPointsFillet(bpy.types.Operator):
|
||||
bl_idname = "curvetools.bezier_points_fillet"
|
||||
bl_label = "Bezier points Fillet"
|
||||
bl_description = "Bezier points Fillet"
|
||||
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
|
||||
|
||||
Fillet_radius : FloatProperty(
|
||||
name="Radius",
|
||||
default=0.25,
|
||||
unit='LENGTH',
|
||||
description="Radius"
|
||||
)
|
||||
Types = [('Round', "Round", "Round"),
|
||||
('Chamfer', "Chamfer", "Chamfer")]
|
||||
Fillet_Type : EnumProperty(
|
||||
name="Type",
|
||||
description="Fillet type",
|
||||
items=Types
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
# general options
|
||||
col = layout.column()
|
||||
col.prop(self, "Fillet_radius")
|
||||
col.prop(self, "Fillet_Type", expand=True)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return (context.object is not None and
|
||||
context.object.type == 'CURVE')
|
||||
|
||||
def execute(self, context):
|
||||
# main function
|
||||
if bpy.ops.object.mode_set.poll():
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
splines = bpy.context.object.data.splines
|
||||
bpy.ops.curve.spline_type_set(type='BEZIER')
|
||||
|
||||
bpy.ops.curve.handle_type_set(type='VECTOR')
|
||||
s = []
|
||||
for spline in splines:
|
||||
n = 0
|
||||
ii = []
|
||||
for p in spline.bezier_points:
|
||||
if p.select_control_point:
|
||||
ii.append(n)
|
||||
n += 1
|
||||
else:
|
||||
n += 1
|
||||
s.append(ii)
|
||||
|
||||
sn = 0
|
||||
for spline in splines:
|
||||
ii = s[sn]
|
||||
n = len(spline.bezier_points)
|
||||
if n > 2:
|
||||
jn = 0
|
||||
for j in ii:
|
||||
|
||||
j += jn
|
||||
|
||||
selected_all = [p for p in spline.bezier_points]
|
||||
|
||||
bpy.ops.curve.select_all(action='DESELECT')
|
||||
|
||||
if j != 0 and j != n - 1:
|
||||
selected_all[j].select_control_point = True
|
||||
selected_all[j + 1].select_control_point = True
|
||||
bpy.ops.curve.subdivide()
|
||||
selected_all = [p for p in spline.bezier_points]
|
||||
selected4 = [selected_all[j - 1], selected_all[j],
|
||||
selected_all[j + 1], selected_all[j + 2]]
|
||||
jn += 1
|
||||
n += 1
|
||||
|
||||
elif j == 0:
|
||||
selected_all[j].select_control_point = True
|
||||
selected_all[j + 1].select_control_point = True
|
||||
bpy.ops.curve.subdivide()
|
||||
selected_all = [p for p in spline.bezier_points]
|
||||
selected4 = [selected_all[n], selected_all[0],
|
||||
selected_all[1], selected_all[2]]
|
||||
jn += 1
|
||||
n += 1
|
||||
|
||||
elif j == n - 1:
|
||||
selected_all[j].select_control_point = True
|
||||
selected_all[j - 1].select_control_point = True
|
||||
bpy.ops.curve.subdivide()
|
||||
selected_all = [p for p in spline.bezier_points]
|
||||
selected4 = [selected_all[0], selected_all[n],
|
||||
selected_all[n - 1], selected_all[n - 2]]
|
||||
|
||||
selected4[2].co = selected4[1].co
|
||||
s1 = Vector(selected4[0].co) - Vector(selected4[1].co)
|
||||
s2 = Vector(selected4[3].co) - Vector(selected4[2].co)
|
||||
s1.normalize()
|
||||
s11 = Vector(selected4[1].co) + s1 * self.Fillet_radius
|
||||
selected4[1].co = s11
|
||||
s2.normalize()
|
||||
s22 = Vector(selected4[2].co) + s2 * self.Fillet_radius
|
||||
selected4[2].co = s22
|
||||
|
||||
if self.Fillet_Type == 'Round':
|
||||
if j != n - 1:
|
||||
selected4[2].handle_right_type = 'VECTOR'
|
||||
selected4[1].handle_left_type = 'VECTOR'
|
||||
selected4[1].handle_right_type = 'ALIGNED'
|
||||
selected4[2].handle_left_type = 'ALIGNED'
|
||||
else:
|
||||
selected4[1].handle_right_type = 'VECTOR'
|
||||
selected4[2].handle_left_type = 'VECTOR'
|
||||
selected4[2].handle_right_type = 'ALIGNED'
|
||||
selected4[1].handle_left_type = 'ALIGNED'
|
||||
if self.Fillet_Type == 'Chamfer':
|
||||
selected4[2].handle_right_type = 'VECTOR'
|
||||
selected4[1].handle_left_type = 'VECTOR'
|
||||
selected4[1].handle_right_type = 'VECTOR'
|
||||
selected4[2].handle_left_type = 'VECTOR'
|
||||
sn += 1
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# BezierDivide Operator
|
||||
|
||||
class BezierDivide(bpy.types.Operator):
|
||||
bl_idname = "curvetools.bezier_spline_divide"
|
||||
bl_label = "Bezier Spline Divide"
|
||||
bl_description = "Bezier Divide (enters edit mode) for Fillet Curves"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
# align_matrix for the invoke
|
||||
align_matrix : Matrix()
|
||||
|
||||
Bezier_t : FloatProperty(
|
||||
name="t (0% - 100%)",
|
||||
default=50.0,
|
||||
min=0.0, soft_min=0.0,
|
||||
max=100.0, soft_max=100.0,
|
||||
description="t (0% - 100%)"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return (context.object is not None and
|
||||
context.object.type == 'CURVE')
|
||||
|
||||
def execute(self, context):
|
||||
# main function
|
||||
if bpy.ops.object.mode_set.poll():
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
|
||||
splines = bpy.context.object.data.splines
|
||||
s = []
|
||||
for spline in splines:
|
||||
bpy.ops.curve.spline_type_set(type='BEZIER')
|
||||
|
||||
n = 0
|
||||
ii = []
|
||||
for p in spline.bezier_points:
|
||||
if p.select_control_point:
|
||||
ii.append(n)
|
||||
n += 1
|
||||
else:
|
||||
n += 1
|
||||
s.append(ii)
|
||||
|
||||
sn = 0
|
||||
for spline in splines:
|
||||
ii = s[sn]
|
||||
n = len(spline.bezier_points)
|
||||
if n > 2:
|
||||
jn = 0
|
||||
for j in ii:
|
||||
|
||||
selected_all = [p for p in spline.bezier_points]
|
||||
|
||||
bpy.ops.curve.select_all(action='DESELECT')
|
||||
|
||||
if (j in ii) and (j + 1 in ii):
|
||||
selected_all[j + jn].select_control_point = True
|
||||
selected_all[j + 1 + jn].select_control_point = True
|
||||
h = Math.subdivide_cubic_bezier(
|
||||
selected_all[j + jn].co, selected_all[j + jn].handle_right,
|
||||
selected_all[j + 1 + jn].handle_left, selected_all[j + 1 + jn].co, self.Bezier_t / 100
|
||||
)
|
||||
bpy.ops.curve.subdivide(1)
|
||||
selected_all = [p for p in spline.bezier_points]
|
||||
selected_all[j + jn].handle_right_type = 'FREE'
|
||||
selected_all[j + jn].handle_right = h[0]
|
||||
selected_all[j + 1 + jn].co = h[2]
|
||||
selected_all[j + 1 + jn].handle_left_type = 'FREE'
|
||||
selected_all[j + 1 + jn].handle_left = h[1]
|
||||
selected_all[j + 1 + jn].handle_right_type = 'FREE'
|
||||
selected_all[j + 1 + jn].handle_right = h[3]
|
||||
selected_all[j + 2 + jn].handle_left_type = 'FREE'
|
||||
selected_all[j + 2 + jn].handle_left = h[4]
|
||||
jn += 1
|
||||
|
||||
if j == n - 1 and (0 in ii) and spline.use_cyclic_u:
|
||||
selected_all[j + jn].select_control_point = True
|
||||
selected_all[0].select_control_point = True
|
||||
h = Math.subdivide_cubic_bezier(
|
||||
selected_all[j + jn].co, selected_all[j + jn].handle_right,
|
||||
selected_all[0].handle_left, selected_all[0].co, self.Bezier_t / 100
|
||||
)
|
||||
bpy.ops.curve.subdivide(1)
|
||||
selected_all = [p for p in spline.bezier_points]
|
||||
selected_all[j + jn].handle_right_type = 'FREE'
|
||||
selected_all[j + jn].handle_right = h[0]
|
||||
selected_all[j + 1 + jn].co = h[2]
|
||||
selected_all[j + 1 + jn].handle_left_type = 'FREE'
|
||||
selected_all[j + 1 + jn].handle_left = h[1]
|
||||
selected_all[j + 1 + jn].handle_right_type = 'FREE'
|
||||
selected_all[j + 1 + jn].handle_right = h[3]
|
||||
selected_all[0].handle_left_type = 'FREE'
|
||||
selected_all[0].handle_left = h[4]
|
||||
|
||||
sn += 1
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# CurveScaleReset Operator
|
||||
|
||||
class CurveScaleReset(bpy.types.Operator):
|
||||
bl_idname = "curvetools.scale_reset"
|
||||
bl_label = "Curve Scale Reset"
|
||||
bl_description = "Curve Scale Reset"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return (context.object is not None and
|
||||
context.object.type == 'CURVE')
|
||||
|
||||
def execute(self, context):
|
||||
# main function
|
||||
current_mode = bpy.context.object.mode
|
||||
|
||||
bpy.ops.object.mode_set(mode = 'OBJECT')
|
||||
|
||||
oldCurve = context.active_object
|
||||
oldCurveName = oldCurve.name
|
||||
|
||||
bpy.ops.object.duplicate_move(OBJECT_OT_duplicate=None, TRANSFORM_OT_translate=None)
|
||||
newCurve = context.active_object
|
||||
newCurve.data.splines.clear()
|
||||
newCurve.scale = (1.0, 1.0, 1.0)
|
||||
|
||||
oldCurve.select_set(True)
|
||||
newCurve.select_set(True)
|
||||
bpy.context.view_layer.objects.active = newCurve
|
||||
bpy.ops.object.join()
|
||||
|
||||
joinCurve = context.active_object
|
||||
joinCurve.name = oldCurveName
|
||||
|
||||
bpy.ops.object.mode_set (mode = current_mode)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
operators = [
|
||||
OperatorCurveInfo,
|
||||
OperatorCurveLength,
|
||||
OperatorSplinesInfo,
|
||||
OperatorSegmentsInfo,
|
||||
OperatorOriginToSpline0Start,
|
||||
OperatorIntersectCurves,
|
||||
OperatorLoftCurves,
|
||||
OperatorSweepCurves,
|
||||
OperatorBirail,
|
||||
OperatorSplinesSetResolution,
|
||||
OperatorSplinesRemoveZeroSegment,
|
||||
OperatorSplinesRemoveShort,
|
||||
OperatorSplinesJoinNeighbouring,
|
||||
ConvertSelectedFacesToBezier,
|
||||
ConvertBezierToSurface,
|
||||
BezierPointsFillet,
|
||||
BezierDivide,
|
||||
CurveScaleReset,
|
||||
]
|
||||
|
|
|
@ -228,7 +228,7 @@ def click(self, context, event):
|
|||
point.select = True
|
||||
|
||||
class PathFinder(bpy.types.Operator):
|
||||
bl_idname = "curvetools2.pathfinder"
|
||||
bl_idname = "curvetools.pathfinder"
|
||||
bl_label = "Path Finder"
|
||||
bl_description = "Path Finder"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
@ -322,4 +322,4 @@ def unregister():
|
|||
bpy.utils.unregister_class(PathFinder)
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
register()
|
||||
|
|
|
@ -5,7 +5,7 @@ from bpy.props import *
|
|||
|
||||
|
||||
|
||||
class CurveTools2SelectedObjectHeader(bpy.types.Header):
|
||||
class curvetoolsSelectedObjectHeader(bpy.types.Header):
|
||||
bl_label = "Selection"
|
||||
bl_space_type = "VIEW_3D"
|
||||
|
||||
|
@ -24,9 +24,9 @@ class CurveTools2SelectedObjectHeader(bpy.types.Header):
|
|||
|
||||
blenderObjectsToAdd = []
|
||||
for blenderObject in blenderSelectedObjects:
|
||||
if not CurveTools2SelectedObject.ListContains(selectedObjects, blenderObject): blenderObjectsToAdd.append(blenderObject)
|
||||
if not curvetoolsSelectedObject.ListContains(selectedObjects, blenderObject): blenderObjectsToAdd.append(blenderObject)
|
||||
for blenderObject in blenderObjectsToAdd:
|
||||
newSelectedObject = CurveTools2SelectedObject(blenderObject)
|
||||
newSelectedObject = curvetoolsSelectedObject(blenderObject)
|
||||
selectedObjects.append(newSelectedObject)
|
||||
|
||||
|
||||
|
@ -39,7 +39,7 @@ class CurveTools2SelectedObjectHeader(bpy.types.Header):
|
|||
row.label(text="Sel: " + str(nrSelectedObjects))
|
||||
|
||||
|
||||
class CurveTools2SelectedObject(bpy.types.PropertyGroup):
|
||||
class curvetoolsSelectedObject(bpy.types.PropertyGroup):
|
||||
name: StringProperty(name = "name", default = "??")
|
||||
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ from bpy_extras.view3d_utils import location_3d_to_region_2d as loc3d2d
|
|||
|
||||
|
||||
|
||||
def get_points(spline):
|
||||
def get_points(spline, matrix_world):
|
||||
|
||||
bezier_points = spline.bezier_points
|
||||
|
||||
|
@ -56,10 +56,10 @@ def get_points(spline):
|
|||
for i in range(segments):
|
||||
inext = (i + 1) % len(bezier_points)
|
||||
|
||||
bezier_points1 = bezier_points[i].co
|
||||
handle1 = bezier_points[i].handle_right
|
||||
handle2 = bezier_points[inext].handle_left
|
||||
bezier_points2 = bezier_points[inext].co
|
||||
bezier_points1 = matrix_world @ bezier_points[i].co
|
||||
handle1 = matrix_world @ bezier_points[i].handle_right
|
||||
handle2 = matrix_world @ bezier_points[inext].handle_left
|
||||
bezier_points2 = matrix_world @ bezier_points[inext].co
|
||||
|
||||
bezier = bezier_points1, handle1, handle2, bezier_points2, r
|
||||
points = interpolate_bezier(*bezier)
|
||||
|
@ -67,9 +67,9 @@ def get_points(spline):
|
|||
|
||||
return point_list
|
||||
|
||||
def draw(self, context, spline, curve_vertcolor):
|
||||
def draw(self, context, spline, curve_vertcolor, matrix_world):
|
||||
|
||||
points = get_points(spline)
|
||||
points = get_points(spline, matrix_world)
|
||||
|
||||
shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR')
|
||||
batch = batch_for_shader(shader, 'POINTS', {"pos": points})
|
||||
|
@ -113,8 +113,9 @@ class ShowCurveResolution(bpy.types.Operator):
|
|||
|
||||
|
||||
splines = context.active_object.data.splines
|
||||
matrix_world = context.active_object.matrix_world
|
||||
for spline in splines:
|
||||
args = (self, context, spline, curve_vertcolor)
|
||||
args = (self, context, spline, curve_vertcolor, matrix_world)
|
||||
|
||||
# Add the region OpenGL drawing callback
|
||||
# draw in view space with 'POST_VIEW' and 'PRE_VIEW'
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
|
||||
bl_info = {
|
||||
"name": "Curve Tools 2",
|
||||
"name": "Curve Tools",
|
||||
"description": "Adds some functionality for bezier/nurbs curve/surface modeling",
|
||||
"author": "Mackraken",
|
||||
"version": (0, 3, 3),
|
||||
|
@ -54,7 +54,6 @@ from . import Properties
|
|||
from . import Operators
|
||||
from . import auto_loft
|
||||
from . import curve_outline
|
||||
from . import curve_remove_doubles
|
||||
from . import PathFinder
|
||||
from . import ShowCurveResolution
|
||||
from . import internal, cad, toolpath, exports
|
||||
|
@ -99,10 +98,10 @@ class SeparateOutline(Operator):
|
|||
return {'FINISHED'}
|
||||
|
||||
|
||||
class CurveTools2Settings(PropertyGroup):
|
||||
class curvetoolsSettings(PropertyGroup):
|
||||
# selection
|
||||
SelectedObjects: CollectionProperty(
|
||||
type=Properties.CurveTools2SelectedObject
|
||||
type=Properties.curvetoolsSelectedObject
|
||||
)
|
||||
NrSelectedObjects: IntProperty(
|
||||
name="NrSelectedObjects",
|
||||
|
@ -224,7 +223,7 @@ class CurveTools2Settings(PropertyGroup):
|
|||
|
||||
|
||||
class VIEW3D_PT_CurvePanel(Panel):
|
||||
bl_label = "Curve Tools 2"
|
||||
bl_label = "Curve Tools"
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = "UI"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
@ -254,22 +253,22 @@ class VIEW3D_PT_CurvePanel(Panel):
|
|||
row = col.row(align=True)
|
||||
|
||||
# A.1 curve info/length
|
||||
row.operator("curvetools2.operatorcurveinfo", text="Curve info")
|
||||
row.operator("curvetools.operatorcurveinfo", text="Curve info")
|
||||
row = col.row(align=True)
|
||||
row.operator("curvetools2.operatorcurvelength", text="Calc Length")
|
||||
row.operator("curvetools.operatorcurvelength", text="Calc Length")
|
||||
row.prop(context.scene.curvetools, "CurveLength", text="")
|
||||
|
||||
# A.2 splines info
|
||||
row = col.row(align=True)
|
||||
row.operator("curvetools2.operatorsplinesinfo", text="Curve splines info")
|
||||
row.operator("curvetools.operatorsplinesinfo", text="Curve splines info")
|
||||
|
||||
# A.3 segments info
|
||||
row = col.row(align=True)
|
||||
row.operator("curvetools2.operatorsegmentsinfo", text="Curve segments info")
|
||||
row.operator("curvetools.operatorsegmentsinfo", text="Curve segments info")
|
||||
|
||||
# A.4 origin to spline0start
|
||||
row = col.row(align=True)
|
||||
row.operator("curvetools2.operatororigintospline0start", text="Set origin to spline start")
|
||||
row.operator("curvetools.operatororigintospline0start", text="Set origin to spline start")
|
||||
|
||||
# Double Curve options
|
||||
box2 = self.layout.box()
|
||||
|
@ -283,7 +282,7 @@ class VIEW3D_PT_CurvePanel(Panel):
|
|||
|
||||
# B.1 curve intersections
|
||||
row = col.row(align=True)
|
||||
row.operator("curvetools2.operatorintersectcurves", text="Intersect curves")
|
||||
row.operator("curvetools.operatorintersectcurves", text="Intersect curves")
|
||||
|
||||
row = col.row(align=True)
|
||||
row.prop(context.scene.curvetools, "LimitDistance", text="LimitDistance")
|
||||
|
@ -309,13 +308,13 @@ class VIEW3D_PT_CurvePanel(Panel):
|
|||
wm = context.window_manager
|
||||
scene = context.scene
|
||||
layout = self.layout
|
||||
layout.operator("curvetools2.create_auto_loft")
|
||||
layout.operator("curvetools.create_auto_loft")
|
||||
lofters = [o for o in scene.objects if "autoloft" in o.keys()]
|
||||
for o in lofters:
|
||||
layout.label(text=o.name)
|
||||
# layout.prop(o, '["autoloft"]', toggle=True)
|
||||
layout.prop(wm, "auto_loft", toggle=True)
|
||||
layout.operator("curvetools2.update_auto_loft_curves")
|
||||
layout.operator("curvetools.update_auto_loft_curves")
|
||||
|
||||
# Advanced options
|
||||
box1 = self.layout.box()
|
||||
|
@ -327,21 +326,19 @@ class VIEW3D_PT_CurvePanel(Panel):
|
|||
row = col.row(align=True)
|
||||
row.operator("object._curve_outline", text="Curve Outline")
|
||||
row = col.row(align=True)
|
||||
row.operator("object.sep_outline", text="Separate Outline")
|
||||
row.operator("object.sep_outline", text="Separate Outline or selected")
|
||||
row = col.row(align=True)
|
||||
row.operator("curve.remove_doubles", text="Remove Doubles")
|
||||
row.operator("curvetools.bezier_points_fillet", text='Fillet')
|
||||
row = col.row(align=True)
|
||||
row.operator("curve.bezier_points_fillet", text='Fillet')
|
||||
row.operator("curvetools.bezier_spline_divide", text='Divide')
|
||||
row = col.row(align=True)
|
||||
row.operator("curve.bezier_spline_divide", text='Divide')
|
||||
row.operator("curvetools.scale_reset", text='Scale Reset')
|
||||
row = col.row(align=True)
|
||||
row.operator("curve.scale_reset", text='Scale Reset')
|
||||
row = col.row(align=True)
|
||||
row.operator("curvetools2.operatorbirail", text="Birail")
|
||||
row.operator("curvetools.operatorbirail", text="Birail")
|
||||
row = col.row(align=True)
|
||||
row.operator("curvetools2.convert_selected_face_to_bezier", text="Convert selected faces to Bezier")
|
||||
row.operator("curvetools.convert_selected_face_to_bezier", text="Convert selected faces to Bezier")
|
||||
row = col.row(align=True)
|
||||
row.operator("curvetools2.convert_bezier_to_surface", text="Convert Bezier to Surface")
|
||||
row.operator("curvetools.convert_bezier_to_surface", text="Convert Bezier to Surface")
|
||||
|
||||
# Extended options
|
||||
box1 = self.layout.box()
|
||||
|
@ -349,13 +346,16 @@ class VIEW3D_PT_CurvePanel(Panel):
|
|||
row = col.row(align=True)
|
||||
row.prop(scene, "UTExtendedDrop", icon="TRIA_DOWN")
|
||||
if EXTENDEDDROP:
|
||||
for operator in cad.operators:
|
||||
row = col.row(align=True)
|
||||
row.operator(operator.bl_idname)
|
||||
|
||||
for operator in toolpath.operators:
|
||||
row = col.row(align=True)
|
||||
row.operator(operator.bl_idname)
|
||||
row = col.row(align=True)
|
||||
row.operator("curve.add_toolpath_offset_curve", text="Offset Curve")
|
||||
row = col.row(align=True)
|
||||
row.operator("curve.bezier_cad_boolean", text="Boolean 2 selected spline")
|
||||
row = col.row(align=True)
|
||||
row.operator("curve.bezier_cad_subdivide", text="Multi Subdivide")
|
||||
row = col.row(align=True)
|
||||
row.operator("curve.add_toolpath_discretize_curve", text="Discretize Curve")
|
||||
row = col.row(align=True)
|
||||
row.operator("curve.bezier_cad_array", text="Array selected spline")
|
||||
|
||||
# Utils Curve options
|
||||
box1 = self.layout.box()
|
||||
|
@ -367,7 +367,7 @@ class VIEW3D_PT_CurvePanel(Panel):
|
|||
row = col.row(align=True)
|
||||
row.label(text="Show point Resolution:")
|
||||
row = col.row(align=True)
|
||||
row.operator("curvetools2.operatorsplinessetresolution", text="Set resolution")
|
||||
row.operator("curvetools.operatorsplinessetresolution", text="Set resolution")
|
||||
row.prop(context.scene.curvetools, "SplineResolution", text="")
|
||||
row = col.row(align=True)
|
||||
row.prop(context.scene.curvetools, "curve_vertcolor", text="")
|
||||
|
@ -378,9 +378,9 @@ class VIEW3D_PT_CurvePanel(Panel):
|
|||
row = col.row(align=True)
|
||||
row.label(text="Remove splines:")
|
||||
row = col.row(align=True)
|
||||
row.operator("curvetools2.operatorsplinesremovezerosegment", text="Remove 0-segments splines")
|
||||
row.operator("curvetools.operatorsplinesremovezerosegment", text="Remove 0-segments splines")
|
||||
row = col.row(align=True)
|
||||
row.operator("curvetools2.operatorsplinesremoveshort", text="Remove short splines")
|
||||
row.operator("curvetools.operatorsplinesremoveshort", text="Remove short splines")
|
||||
row = col.row(align=True)
|
||||
row.prop(context.scene.curvetools, "SplineRemoveLength", text="Threshold remove")
|
||||
|
||||
|
@ -388,7 +388,7 @@ class VIEW3D_PT_CurvePanel(Panel):
|
|||
row = col.row(align=True)
|
||||
row.label(text="Join splines:")
|
||||
row = col.row(align=True)
|
||||
row.operator("curvetools2.operatorsplinesjoinneighbouring", text="Join neighbouring splines")
|
||||
row.operator("curvetools.operatorsplinesjoinneighbouring", text="Join neighbouring splines")
|
||||
row = col.row(align=True)
|
||||
row.prop(context.scene.curvetools, "SplineJoinDistance", text="Threshold join")
|
||||
row = col.row(align=True)
|
||||
|
@ -404,7 +404,7 @@ class VIEW3D_PT_CurvePanel(Panel):
|
|||
row.prop(context.scene.curvetools, "path_color", text="")
|
||||
row.prop(context.scene.curvetools, "path_thickness", text="")
|
||||
row = col.row(align=True)
|
||||
row.operator("curvetools2.pathfinder", text="Run Path Finder [ESC]")
|
||||
row.operator("curvetools.pathfinder", text="Run Path Finder [ESC]")
|
||||
row = col.row(align=True)
|
||||
row.label(text="ESC or TAB - exit from PathFinder")
|
||||
row = col.row(align=True)
|
||||
|
@ -424,7 +424,7 @@ panels = (
|
|||
|
||||
|
||||
def update_panel(self, context):
|
||||
message = "Curve Tools 2: Updating Panel locations has failed"
|
||||
message = "Curve Tools: Updating Panel locations has failed"
|
||||
try:
|
||||
for panel in panels:
|
||||
if "bl_rna" in panel.__dict__:
|
||||
|
@ -468,26 +468,11 @@ def menu_file_import(self, context):
|
|||
self.layout.operator(operator.bl_idname)
|
||||
|
||||
# REGISTER
|
||||
classes = cad.operators + toolpath.operators + exports.operators + [
|
||||
Properties.CurveTools2SelectedObject,
|
||||
classes = cad.operators + toolpath.operators + exports.operators + Operators.operators + [
|
||||
Properties.curvetoolsSelectedObject,
|
||||
CurveAddonPreferences,
|
||||
CurveTools2Settings,
|
||||
Operators.OperatorCurveInfo,
|
||||
Operators.OperatorCurveLength,
|
||||
Operators.OperatorSplinesInfo,
|
||||
Operators.OperatorSegmentsInfo,
|
||||
Operators.OperatorOriginToSpline0Start,
|
||||
Operators.OperatorIntersectCurves,
|
||||
Operators.OperatorLoftCurves,
|
||||
Operators.OperatorSweepCurves,
|
||||
Operators.OperatorBirail,
|
||||
Operators.OperatorSplinesSetResolution,
|
||||
Operators.OperatorSplinesRemoveZeroSegment,
|
||||
Operators.OperatorSplinesRemoveShort,
|
||||
Operators.OperatorSplinesJoinNeighbouring,
|
||||
curvetoolsSettings,
|
||||
SeparateOutline,
|
||||
Operators.ConvertSelectedFacesToBezier,
|
||||
Operators.ConvertBezierToSurface,
|
||||
PathFinder.PathFinder,
|
||||
ShowCurveResolution.ShowCurveResolution,
|
||||
]
|
||||
|
@ -534,11 +519,9 @@ def register():
|
|||
|
||||
curve_outline.register()
|
||||
|
||||
curve_remove_doubles.register()
|
||||
|
||||
bpy.types.TOPBAR_MT_file_export.append(menu_file_export)
|
||||
|
||||
bpy.types.Scene.curvetools = bpy.props.PointerProperty(type=CurveTools2Settings)
|
||||
bpy.types.Scene.curvetools = bpy.props.PointerProperty(type=curvetoolsSettings)
|
||||
|
||||
update_panel(None, bpy.context)
|
||||
|
||||
|
@ -555,8 +538,6 @@ def unregister():
|
|||
|
||||
curve_outline.unregister()
|
||||
|
||||
curve_remove_doubles.unregister()
|
||||
|
||||
bpy.types.TOPBAR_MT_file_export.remove(menu_file_export)
|
||||
|
||||
for panel in panels:
|
||||
|
|
|
@ -7,7 +7,7 @@ from curve_tools import Util
|
|||
|
||||
|
||||
class OperatorAutoLoftCurves(Operator):
|
||||
bl_idname = "curvetools2.create_auto_loft"
|
||||
bl_idname = "curvetools.create_auto_loft"
|
||||
bl_label = "Loft"
|
||||
bl_description = "Lofts selected curves"
|
||||
|
||||
|
@ -44,7 +44,7 @@ class OperatorAutoLoftCurves(Operator):
|
|||
|
||||
class AutoLoftModalOperator(Operator):
|
||||
"""Auto Loft"""
|
||||
bl_idname = "curvetools2.update_auto_loft_curves"
|
||||
bl_idname = "curvetools.update_auto_loft_curves"
|
||||
bl_label = "Update Auto Loft"
|
||||
bl_description = "Update Lofts selected curves"
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ bl_info = {
|
|||
|
||||
import bpy
|
||||
from . import internal
|
||||
from . import Util
|
||||
|
||||
class Fillet(bpy.types.Operator):
|
||||
bl_idname = 'curve.bezier_cad_fillet'
|
||||
|
@ -40,7 +41,7 @@ class Fillet(bpy.types.Operator):
|
|||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return internal.curveObject()
|
||||
return Util.Selected1OrMoreCurves()
|
||||
|
||||
def execute(self, context):
|
||||
splines = internal.getSelectedSplines(True, True, True)
|
||||
|
@ -65,22 +66,29 @@ class Boolean(bpy.types.Operator):
|
|||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return internal.curveObject()
|
||||
return Util.Selected1OrMoreCurves()
|
||||
|
||||
def execute(self, context):
|
||||
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'}
|
||||
splines = internal.getSelectedSplines(True, True)
|
||||
if len(splines) != 2:
|
||||
self.report({'WARNING'}, 'Invalid selection')
|
||||
self.report({'WARNING'}, 'Invalid selection. Only work to selected two spline.')
|
||||
return {'CANCELLED'}
|
||||
bpy.ops.curve.spline_type_set(type='BEZIER')
|
||||
splineA = bpy.context.object.data.splines.active
|
||||
splineB = splines[0] if (splines[1] == splineA) else splines[1]
|
||||
if not internal.bezierBooleanGeometry(splineA, splineB, self.operation):
|
||||
self.report({'WARNING'}, 'Invalid selection')
|
||||
self.report({'WARNING'}, 'Invalid selection. Only work to selected two spline.')
|
||||
return {'CANCELLED'}
|
||||
|
||||
bpy.ops.object.mode_set (mode = current_mode)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
class Intersection(bpy.types.Operator):
|
||||
|
@ -90,7 +98,7 @@ class Intersection(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)
|
||||
|
@ -108,7 +116,7 @@ class MergeEnds(bpy.types.Operator):
|
|||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return internal.curveObject()
|
||||
return Util.Selected1OrMoreCurves()
|
||||
|
||||
def execute(self, context):
|
||||
points = []
|
||||
|
@ -161,9 +169,13 @@ class Subdivide(bpy.types.Operator):
|
|||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return internal.curveObject()
|
||||
return Util.Selected1OrMoreCurves()
|
||||
|
||||
def execute(self, context):
|
||||
current_mode = bpy.context.object.mode
|
||||
|
||||
bpy.ops.object.mode_set(mode = 'EDIT')
|
||||
|
||||
segments = internal.bezierSegments(bpy.context.object.data.splines, True)
|
||||
if len(segments) == 0:
|
||||
self.report({'WARNING'}, 'Nothing selected')
|
||||
|
@ -176,6 +188,8 @@ class Subdivide(bpy.types.Operator):
|
|||
for segment in segments:
|
||||
segment['cuts'].extend(cuts)
|
||||
internal.subdivideBezierSegments(segments)
|
||||
|
||||
bpy.ops.object.mode_set (mode = current_mode)
|
||||
return {'FINISHED'}
|
||||
|
||||
class Array(bpy.types.Operator):
|
||||
|
@ -183,14 +197,14 @@ 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=(0.0, 0.0, -1.0), size=3)
|
||||
offset: bpy.props.FloatVectorProperty(name='Offset', unit='LENGTH', description='Vector between to copies', subtype='DIRECTION', default=(1.0, 0.0, 0.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)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return internal.curveObject()
|
||||
return Util.Selected1OrMoreCurves()
|
||||
|
||||
def execute(self, context):
|
||||
splines = internal.getSelectedSplines(True, True)
|
||||
|
@ -207,7 +221,7 @@ class Circle(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)
|
||||
|
@ -231,7 +245,7 @@ class Length(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)
|
||||
|
|
Loading…
Reference in New Issue