Skip to content
Snippets Groups Projects
operators.py 49.3 KiB
Newer Older
  • Learn to ignore specific revisions
  •                 if select_points[key][-1] == select_points[key][0]-1:
                        select_points[key].pop()
    
                    for i in select_points[key][1:]+[select_points[key][0]-1]:
                        if i != 0:
                            spline = curve.data.splines.new(spline_points[key][i][1])
                            spline.points.add(i-num)
    
                            for j in range(num, i):
                                point = spline.points[j-num]
    
                                point.co = spline_points[key][j][0]
                            point = spline.points[-1]
                            point.co = spline_points[key][i][0]
                            num=i
    
    class SeparateOutline(bpy.types.Operator):
        bl_idname = "curvetools.sep_outline"
        bl_label = "Separate Outline"
        bl_options = {'REGISTER', 'UNDO'}
        bl_description = "Makes 'Outline' separate mesh"
    
        @classmethod
        def poll(cls, context):
            return util.Selected1OrMoreCurves()
    
        def execute(self, context):
            bpy.ops.object.mode_set(mode = 'EDIT')
            bpy.ops.curve.separate()
    
            return {'FINISHED'}
    
    class CurveBoolean(bpy.types.Operator):
        bl_idname = "curvetools.bezier_curve_boolean"
        bl_description = "Curve Boolean"
        bl_label = "Curve Boolean"
        bl_options = {'REGISTER', 'UNDO'}
    
        operation: bpy.props.EnumProperty(name='Type', items=[
            ('UNION', 'Union', 'Boolean OR', 0),
            ('INTERSECTION', 'Intersection', 'Boolean AND', 1),
    
            ('DIFFERENCE', 'Difference', 'Active minus Selected', 2),
    
        number : IntProperty(
                name="Spline Number",
                default=1,
                min=1,
                description="Spline Number"
                )
    
    
        @classmethod
        def poll(cls, context):
            return util.Selected1OrMoreCurves()
    
        def draw(self, context):
            layout = self.layout
    
            # general options
            col = layout.column()
            col.prop(self, "operation")
            if self.operation == 'DIFFERENCE':
                col.prop(self, "number")
    
    
        def execute(self, context):
            current_mode = bpy.context.object.mode
    
            if bpy.ops.object.mode_set.poll():
                bpy.ops.object.mode_set(mode = 'OBJECT')
    
            selected_Curves = util.GetSelectedCurves()
            len_selected_curves = len(selected_Curves)
            if len_selected_curves < 2:
                return {'FINISHED'}
    
            max_number = 0
            for iCurve in range(0, len_selected_curves):
                len_splines = len(selected_Curves[iCurve].data.splines)
                max_number += len_splines
    
            if self.number < min_number:
                self.number = min_number
            if self.number > max_number:
                self.number = max_number
    
            j = 0
            first_curve = 0
            first_spline = 0
            for iCurve in range(0, len_selected_curves):
                len_splines = len(selected_Curves[iCurve].data.splines)
                for iSpline in range(0, len_splines):
                    if j == self.number:
                        first_curve = iCurve
                        first_spline = iSpline
                    j += 1
    
            spline1 = selected_Curves[first_curve].data.splines[first_spline]
            matrix_world1 = selected_Curves[first_curve].matrix_world
    
            len_spline1 = len(spline1.bezier_points)
    
            dataCurve = bpy.data.curves.new(self.operation, type='CURVE')
            dataCurve.dimensions = '2D'
            newSpline1 = dataCurve.splines.new(type='BEZIER')
            newSpline1.use_cyclic_u = True
            newSpline1.bezier_points.add(len_spline1 - 1)
            for n in range(0, len_spline1):
                newSpline1.bezier_points[n].co = matrix_world1 @ spline1.bezier_points[n].co
                newSpline1.bezier_points[n].handle_left_type = spline1.bezier_points[n].handle_left_type
                newSpline1.bezier_points[n].handle_left = matrix_world1 @ spline1.bezier_points[n].handle_left
                newSpline1.bezier_points[n].handle_right_type = spline1.bezier_points[n].handle_right_type
                newSpline1.bezier_points[n].handle_right = matrix_world1 @ spline1.bezier_points[n].handle_right
    
            Curve = object_utils.object_data_add(context, dataCurve)
            bpy.context.view_layer.objects.active = Curve
            Curve.select_set(True)
    
            for iCurve in range(0, len_selected_curves):
                matrix_world = selected_Curves[iCurve].matrix_world
                len_splines = len(selected_Curves[iCurve].data.splines)
    
                for iSpline in range(0, len_splines):
                    if iCurve == first_curve and iSpline == first_spline:
                        continue
                    spline = selected_Curves[iCurve].data.splines[iSpline]
    
                    len_spline = len(spline.bezier_points)
                    newSpline = dataCurve.splines.new(type='BEZIER')
                    newSpline.use_cyclic_u = True
                    newSpline.bezier_points.add(len_spline - 1)
                    for n in range(0, len_spline):
                        newSpline.bezier_points[n].co = matrix_world @ spline.bezier_points[n].co
                        newSpline.bezier_points[n].handle_left_type = spline.bezier_points[n].handle_left_type
                        newSpline.bezier_points[n].handle_left = matrix_world @ spline.bezier_points[n].handle_left
                        newSpline.bezier_points[n].handle_right_type = spline.bezier_points[n].handle_right_type
                        newSpline.bezier_points[n].handle_right = matrix_world @ spline.bezier_points[n].handle_right
    
                    bpy.ops.object.mode_set(mode = 'EDIT')
                    bpy.ops.curve.select_all(action='SELECT')
                    splines = internal.getSelectedSplines(True, True)
    
                    if len(splines) < 2:
                       continue
    
                    splineA = splines[0]
                    splineB = splines[1]
                    dataCurve.splines.active = newSpline1
    
                    if not internal.bezierBooleanGeometry(splineA, splineB, self.operation):
    
                        self.report({'WARNING'}, 'Invalid selection.')
                        return {'CANCELLED'}
    
            bpy.ops.object.mode_set(mode = 'EDIT')
            bpy.ops.curve.select_all(action='SELECT')
    
            return {'FINISHED'}
    
    # ----------------------------
    # Set first points operator
    class SetFirstPoints(bpy.types.Operator):
        bl_idname = "curvetools.set_first_points"
        bl_label = "Set first points"
        bl_description = "Set the selected points as the first point of each spline"
        bl_options = {'REGISTER', 'UNDO'}
    
        @classmethod
        def poll(cls, context):
            return util.Selected1OrMoreCurves()
    
        def execute(self, context):
            splines_to_invert = []
    
            curve = bpy.context.object
    
            bpy.ops.object.mode_set('INVOKE_REGION_WIN', mode='EDIT')
    
            # Check non-cyclic splines to invert
            for i in range(len(curve.data.splines)):
                b_points = curve.data.splines[i].bezier_points
    
                if i not in self.cyclic_splines:  # Only for non-cyclic splines
                    if b_points[len(b_points) - 1].select_control_point:
                        splines_to_invert.append(i)
    
            # Reorder points of cyclic splines, and set all handles to "Automatic"
    
            # Check first selected point
            cyclic_splines_new_first_pt = {}
            for i in self.cyclic_splines:
                sp = curve.data.splines[i]
    
                for t in range(len(sp.bezier_points)):
                    bp = sp.bezier_points[t]
                    if bp.select_control_point or bp.select_right_handle or bp.select_left_handle:
                        cyclic_splines_new_first_pt[i] = t
                        break  # To take only one if there are more
    
            # Reorder
            for spline_idx in cyclic_splines_new_first_pt:
                sp = curve.data.splines[spline_idx]
    
                spline_old_coords = []
                for bp_old in sp.bezier_points:
                    coords = (bp_old.co[0], bp_old.co[1], bp_old.co[2])
    
                    left_handle_type = str(bp_old.handle_left_type)
                    left_handle_length = float(bp_old.handle_left.length)
                    left_handle_xyz = (
                            float(bp_old.handle_left.x),
                            float(bp_old.handle_left.y),
                            float(bp_old.handle_left.z)
                            )
                    right_handle_type = str(bp_old.handle_right_type)
                    right_handle_length = float(bp_old.handle_right.length)
                    right_handle_xyz = (
                            float(bp_old.handle_right.x),
                            float(bp_old.handle_right.y),
                            float(bp_old.handle_right.z)
                            )
                    spline_old_coords.append(
                            [coords, left_handle_type,
                            right_handle_type, left_handle_length,
                            right_handle_length, left_handle_xyz,
                            right_handle_xyz]
                            )
    
                for t in range(len(sp.bezier_points)):
                    bp = sp.bezier_points
    
                    if t + cyclic_splines_new_first_pt[spline_idx] + 1 <= len(bp) - 1:
                        new_index = t + cyclic_splines_new_first_pt[spline_idx] + 1
                    else:
                        new_index = t + cyclic_splines_new_first_pt[spline_idx] + 1 - len(bp)
    
                    bp[t].co = Vector(spline_old_coords[new_index][0])
    
                    bp[t].handle_left.length = spline_old_coords[new_index][3]
                    bp[t].handle_right.length = spline_old_coords[new_index][4]
    
                    bp[t].handle_left_type = "FREE"
                    bp[t].handle_right_type = "FREE"
    
                    bp[t].handle_left.x = spline_old_coords[new_index][5][0]
                    bp[t].handle_left.y = spline_old_coords[new_index][5][1]
                    bp[t].handle_left.z = spline_old_coords[new_index][5][2]
    
                    bp[t].handle_right.x = spline_old_coords[new_index][6][0]
                    bp[t].handle_right.y = spline_old_coords[new_index][6][1]
                    bp[t].handle_right.z = spline_old_coords[new_index][6][2]
    
                    bp[t].handle_left_type = spline_old_coords[new_index][1]
                    bp[t].handle_right_type = spline_old_coords[new_index][2]
    
            # Invert the non-cyclic splines designated above
            for i in range(len(splines_to_invert)):
                bpy.ops.curve.select_all('INVOKE_REGION_WIN', action='DESELECT')
    
                bpy.ops.object.editmode_toggle('INVOKE_REGION_WIN')
                curve.data.splines[splines_to_invert[i]].bezier_points[0].select_control_point = True
                bpy.ops.object.editmode_toggle('INVOKE_REGION_WIN')
    
                bpy.ops.curve.switch_direction()
    
            bpy.ops.curve.select_all('INVOKE_REGION_WIN', action='DESELECT')
    
            # Keep selected the first vert of each spline
            bpy.ops.object.editmode_toggle('INVOKE_REGION_WIN')
            for i in range(len(curve.data.splines)):
                if not curve.data.splines[i].use_cyclic_u:
                    bp = curve.data.splines[i].bezier_points[0]
                else:
                    bp = curve.data.splines[i].bezier_points[
                                                            len(curve.data.splines[i].bezier_points) - 1
                                                            ]
    
                bp.select_control_point = True
                bp.select_right_handle = True
                bp.select_left_handle = True
    
            bpy.ops.object.editmode_toggle('INVOKE_REGION_WIN')
    
            return {'FINISHED'}
    
        def invoke(self, context, event):
            curve = bpy.context.object
    
            # Check if all curves are Bezier, and detect which ones are cyclic
            self.cyclic_splines = []
            for i in range(len(curve.data.splines)):
                if curve.data.splines[i].type != "BEZIER":
                    self.report({'WARNING'}, "All splines must be Bezier type")
    
                    return {'CANCELLED'}
                else:
                    if curve.data.splines[i].use_cyclic_u:
                        self.cyclic_splines.append(i)
    
            self.execute(context)
            self.report({'INFO'}, "First points have been set")
    
    
    def register():
        for cls in classes:
            bpy.utils.register_class(operators)
    
    def unregister():
        for cls in classes:
            bpy.utils.unregister_class(operators)
    
    if __name__ == "__main__":
        register()
    
    operators = [
        OperatorCurveInfo,
        OperatorCurveLength,
        OperatorSplinesInfo,
        OperatorSegmentsInfo,
        OperatorOriginToSpline0Start,
        OperatorIntersectCurves,
        OperatorLoftCurves,
        OperatorSweepCurves,
        OperatorBirail,
        OperatorSplinesSetResolution,
        OperatorSplinesRemoveZeroSegment,
        OperatorSplinesRemoveShort,
        OperatorSplinesJoinNeighbouring,
        ConvertSelectedFacesToBezier,
        ConvertBezierToSurface,
        BezierPointsFillet,
        BezierDivide,
        CurveScaleReset,