Skip to content
Snippets Groups Projects
beveltaper_curve.py 13.9 KiB
Newer Older
  • Learn to ignore specific revisions
  • # SPDX-License-Identifier: GPL-2.0-or-later
    
    
    # DevBo Task: https://developer.blender.org/T37377
    
    
    bl_info = {
        "name": "Bevel/Taper Curve",
        "author": "Cmomoney",
    
        "blender": (2, 80, 0),
    
        "location": "View3D > Object > Bevel/Taper",
        "description": "Adds bevel and/or taper curve to active curve",
        "warning": "",
    
        "doc_url": "{BLENDER_MANUAL_URL}/addons/add_curve/extra_objects.html",
    
    from bpy.types import (
            Operator,
            Menu,
            )
    from bpy.props import (
            BoolProperty,
            FloatProperty,
            IntProperty,
            )
    from bpy_extras.object_utils import (
            AddObjectHelper,
            object_data_add,
            )
    
    def add_taper(self, context):
    
        scale_ends1 = self.scale_ends1
        scale_ends2 = self.scale_ends2
        scale_mid = self.scale_mid
    
        verts = [
                (-2.0, 1.0 * scale_ends1, 0.0, 1.0),
                (-1.0, 0.75 * scale_mid, 0.0, 1.0),
                (0.0, 1.5 * scale_mid, 0.0, 1.0),
                (1.0, 0.75 * scale_mid, 0.0, 1.0),
                (2.0, 1.0 * scale_ends2, 0.0, 1.0)
                ]
    
        make_path(self, context, verts)
    
    
    
    def add_type5(self, context):
    
        scale_x = self.scale_x
        scale_y = self.scale_y
    
        verts = [
                [0.0 * scale_x, 0.049549 * scale_y,
                0.0, 0.031603 * scale_x, 0.047013 * scale_y,
                0.0, 0.05 * scale_x, 0.0 * scale_y, 0.0,
                0.031603 * scale_x, -0.047013 * scale_y,
                0.0, 0.0 * scale_x, -0.049549 * scale_y,
                0.0, -0.031603 * scale_x, -0.047013 * scale_y,
                0.0, -0.05 * scale_x, -0.0 * scale_y, 0.0,
                -0.031603 * scale_x, 0.047013 * scale_y, 0.0]
                ]
        lhandles = [
                [(-0.008804 * scale_x, 0.049549 * scale_y, 0.0),
                (0.021304 * scale_x, 0.02119 * scale_y, 0.0),
                (0.05 * scale_x, 0.051228 * scale_y, 0.0),
                (0.036552 * scale_x, -0.059423 * scale_y, 0.0),
                (0.008804 * scale_x, -0.049549 * scale_y, 0.0),
                (-0.021304 * scale_x, -0.02119 * scale_y, 0.0),
                (-0.05 * scale_x, -0.051228 * scale_y, 0.0),
                (-0.036552 * scale_x, 0.059423 * scale_y, 0.0)]
                ]
        rhandles = [
                [(0.008803 * scale_x, 0.049549 * scale_y, 0.0),
                (0.036552 * scale_x, 0.059423 * scale_y, 0.0),
                (0.05 * scale_x, -0.051228 * scale_y, 0.0),
                (0.021304 * scale_x, -0.02119 * scale_y, 0.0),
                (-0.008803 * scale_x, -0.049549 * scale_y, 0.0),
                (-0.036552 * scale_x, -0.059423 * scale_y, 0.0),
                (-0.05 * scale_x, 0.051228 * scale_y, 0.0),
                (-0.021304 * scale_x, 0.02119 * scale_y, 0.0)]
                ]
    
        make_curve(self, context, verts, lhandles, rhandles)
    
    
    
    def add_type4(self, context):
    
        scale_x = self.scale_x
        scale_y = self.scale_y
    
        verts = [
                [-0.0 * scale_x, 0.017183 * scale_y,
                0.0, 0.05 * scale_x, 0.0 * scale_y,
                0.0, 0.0 * scale_x, -0.017183 * scale_y,
                0.0, -0.05 * scale_x, -0.0 * scale_y, 0.0]
                ]
        lhandles = [
                [(-0.017607 * scale_x, 0.017183 * scale_y, 0.0),
                (0.05 * scale_x, 0.102456 * scale_y, 0.0),
                (0.017607 * scale_x, -0.017183 * scale_y, 0.0),
                (-0.05 * scale_x, -0.102456 * scale_y, 0.0)]
                ]
        rhandles = [
                [(0.017607 * scale_x, 0.017183 * scale_y, 0.0),
                (0.05 * scale_x, -0.102456 * scale_y, 0.0),
                (-0.017607 * scale_x, -0.017183 * scale_y, 0.0),
                (-0.05 * scale_x, 0.102456 * scale_y, 0.0)]
                ]
    
        make_curve(self, context, verts, lhandles, rhandles)
    
    
    
    def add_type3(self, context):
    
        scale_x = self.scale_x
        scale_y = self.scale_y
    
        verts = [
                [-0.017183 * scale_x, 0.0 * scale_y,
                0.0, 0.0 * scale_x, 0.05 * scale_y,
                0.0, 0.017183 * scale_x, 0.0 * scale_y,
                0.0, 0.0 * scale_x, -0.05 * scale_y, 0.0]
                ]
        lhandles = [
                [(-0.017183 * scale_x, -0.017607 * scale_y, 0.0),
                (-0.102456 * scale_x, 0.05 * scale_y, 0.0),
                (0.017183 * scale_x, 0.017607 * scale_y, 0.0),
                (0.102456 * scale_x, -0.05 * scale_y, 0.0)]
                ]
        rhandles = [
                [(-0.017183 * scale_x, 0.017607 * scale_y, 0.0),
                (0.102456 * scale_x, 0.05 * scale_y, 0.0),
                (0.017183 * scale_x, -0.017607 * scale_y, 0.0),
                (-0.102456 * scale_x, -0.05 * scale_y, 0.0)]
                ]
    
        make_curve(self, context, verts, lhandles, rhandles)
    
    
    
    def add_type2(self, context):
    
        scale_x = self.scale_x
        scale_y = self.scale_y
    
        verts = [
                [-0.05 * scale_x, 0.0 * scale_y,
                0.0, 0.0 * scale_x, 0.05 * scale_y,
                0.0, 0.05 * scale_x, 0.0 * scale_y,
                0.0, 0.0 * scale_x, -0.05 * scale_y, 0.0]
                ]
        lhandles = [
                [(-0.05 * scale_x, -0.047606 * scale_y, 0.0),
                (-0.047606 * scale_x, 0.05 * scale_y, 0.0),
                (0.05 * scale_x, 0.047607 * scale_y, 0.0),
                (0.047606 * scale_x, -0.05 * scale_y, 0.0)]
                ]
        rhandles = [
                [(-0.05 * scale_x, 0.047607 * scale_y, 0.0),
                (0.047607 * scale_x, 0.05 * scale_y, 0.0),
                (0.05 * scale_x, -0.047607 * scale_y, 0.0),
                (-0.047607 * scale_x, -0.05 * scale_y, 0.0)]
                ]
    
        make_curve(self, context, verts, lhandles, rhandles)
    
    
    
    def add_type1(self, context):
    
        scale_x = self.scale_x
        scale_y = self.scale_y
    
        verts = [
                [-0.05 * scale_x, 0.0 * scale_y,
                0.0, 0.0 * scale_x, 0.05 * scale_y,
                0.0, 0.05 * scale_x, 0.0 * scale_y,
                0.0, 0.0 * scale_x, -0.05 * scale_y, 0.0]
                ]
        lhandles = [
                [(-0.05 * scale_x, -0.027606 * scale_y, 0.0),
                (-0.027606 * scale_x, 0.05 * scale_y, 0.0),
                (0.05 * scale_x, 0.027606 * scale_y, 0.0),
                (0.027606 * scale_x, -0.05 * scale_y, 0.0)]
                ]
        rhandles = [
                [(-0.05 * scale_x, 0.027607 * scale_y, 0.0),
                (0.027607 * scale_x, 0.05 * scale_y, 0.0),
                (0.05 * scale_x, -0.027607 * scale_y, 0.0),
                (-0.027607 * scale_x, -0.05 * scale_y, 0.0)]
                ]
    
        make_curve(self, context, verts, lhandles, rhandles)
    
    
    
    def make_path(self, context, verts):
    
        target = bpy.context.view_layer.objects.active
    
        bpy.ops.curve.primitive_nurbs_path_add(
    
                align='WORLD', enter_editmode=False, location=(0, 0, 0)
    
        target.data.taper_object = bpy.context.view_layer.objects.active
        taper = bpy.context.view_layer.objects.active
    
        taper.name = target.name + '_Taper'
    
        bpy.context.view_layer.objects.active = target
    
        points = taper.data.splines[0].points
    
        for i in range(len(verts)):
            points[i].co = verts[i]
    
    
    
    def make_curve(self, context, verts, lh, rh):
    
        target = bpy.context.view_layer.objects.active
    
        curve_data = bpy.data.curves.new(
                            name=target.name + '_Bevel', type='CURVE'
                            )
    
        curve_data.dimensions = '3D'
    
        for p in range(len(verts)):
            c = 0
            spline = curve_data.splines.new(type='BEZIER')
            spline.use_cyclic_u = True
    
            spline.bezier_points.add(int(len(verts[p]) / 3 - 1))
    
            spline.bezier_points.foreach_set('co', verts[p])
    
            for bp in spline.bezier_points:
                bp.handle_left_type = 'ALIGNED'
                bp.handle_right_type = 'ALIGNED'
                bp.handle_left.xyz = lh[p][c]
                bp.handle_right.xyz = rh[p][c]
                c += 1
    
        object_data_add(context, curve_data, operator=self)
    
        target.data.bevel_object = bpy.context.view_layer.objects.active
        bpy.context.view_layer.objects.active = target
    
    
    class add_tapercurve(Operator):
    
        bl_idname = "curve.tapercurve"
        bl_label = "Add Curve as Taper"
    
        bl_description = ("Add taper curve to Active Curve\n"
                          "Needs an existing Active Curve")
    
        bl_options = {'REGISTER', 'UNDO', 'PRESET'}
    
        scale_ends1 : FloatProperty(
    
                name="End Width Left",
                description="Adjust left end taper",
                default=0.0,
                min=0.0
                )
    
        scale_ends2 : FloatProperty(
    
                name="End Width Right",
                description="Adjust right end taper",
                default=0.0,
                min=0.0
                )
    
        scale_mid : FloatProperty(
    
                name="Center Width",
                description="Adjust taper at center",
                default=1.0,
                min=0.0
                )
    
        link1 : BoolProperty(
    
                name="Link Ends",
                description="Link the End Width Left / Right settings\n"
                            "End Width Left will be editable ",
                default=True
                )
    
        link2 : BoolProperty(
    
                name="Link Ends / Center",
                description="Link the End Widths with the Center Width",
                default=False
                )
    
        diff : FloatProperty(
    
                name="Difference",
                default=1,
                description="Difference between ends and center while linked"
                )
    
        edit_mode : BoolProperty(
                name="Show in edit mode",
                default=True,
                description="Show in edit mode"
                )
    
    
        @classmethod
        def poll(cls, context):
            obj = context.active_object
            return context.mode == 'OBJECT' and obj and obj.type == "CURVE"
    
        def draw(self, context):
            layout = self.layout
    
            col = layout.column(align=True)
    
            col.label(text="Settings:")
    
            split = layout.split(factor=0.95, align=True)
    
            split.active = not self.link2
            col = split.column(align=True)
            col.prop(self, "scale_ends1")
    
            row = split.row(align=True)
            row.scale_y = 2.0
            col_sub = col.column(align=True)
            col_sub.active = not self.link1
            col_sub.prop(self, "scale_ends2")
            row.prop(self, "link1", toggle=True, text="", icon="LINKED")
    
    
            split = layout.split(factor=0.95, align=True)
    
            col = split.column(align=True)
            col.prop(self, "scale_mid")
    
            row = split.row(align=True)
            row.scale_y = 2.0
            col_sub = col.column(align=True)
            col_sub.active = self.link2
            row.prop(self, "link2", toggle=True, text="", icon="LINKED")
            col_sub.prop(self, "diff")
    
            col = layout.column()
            col.row().prop(self, "edit_mode", expand=True)
    
    
        def execute(self, context):
            if self.link1:
                self.scale_ends2 = self.scale_ends1
    
                self.scale_ends2 = self.scale_ends1 = self.scale_mid - self.diff
    
    
            add_taper(self, context)
    
            if self.edit_mode:
                bpy.ops.object.mode_set(mode = 'EDIT')
            else:
                bpy.ops.object.mode_set(mode = 'OBJECT')
    
            return {'FINISHED'}
    
    
    class add_bevelcurve(Operator, AddObjectHelper):
        bl_idname = "curve.bevelcurve"
        bl_label = "Add Curve as Bevel"
    
        bl_description = ("Add bevel curve to Active Curve\n"
                          "Needs an existing Active Curve")
    
        bl_options = {'REGISTER', 'UNDO', 'PRESET'}
    
        types : IntProperty(
    
                name="Type",
                description="Type of bevel curve",
                default=1,
                min=1, max=5
                )
    
        scale_x : FloatProperty(
    
                name="Scale X",
                description="Scale on X axis",
                default=1.0
                )
    
        scale_y : FloatProperty(
    
                name="Scale Y",
                description="Scale on Y axis",
                default=1.0
                )
    
        link : BoolProperty(
    
                name="Link XY",
                description="Link the Scale on X/Y axis",
                default=True
                )
    
        edit_mode : BoolProperty(
                name="Show in edit mode",
                default=True,
                description="Show in edit mode"
                )
    
    
        @classmethod
        def poll(cls, context):
            obj = context.active_object
            return context.mode == 'OBJECT' and obj and obj.type == "CURVE"
    
        def draw(self, context):
            layout = self.layout
    
            col = layout.column(align=True)
            # AddObjectHelper props
    
            col.prop(self, "align")
    
            col.prop(self, "location")
            col.prop(self, "rotation")
    
            col = layout.column(align=True)
    
            col.label(text = "Settings:")
    
            split = layout.split(factor=0.95, align=True)
    
            col = split.column(align=True)
            col.prop(self, "scale_x")
            row = split.row(align=True)
            row.scale_y = 2.0
            col.prop(self, "scale_y")
            row.prop(self, "link", toggle=True, text="", icon="LINKED")
    
            col = layout.column()
            col.row().prop(self, "edit_mode", expand=True)
    
    
        def execute(self, context):
            if self.link:
                self.scale_y = self.scale_x
    
                add_type1(self, context)
    
                add_type2(self, context)
    
                add_type3(self, context)
    
                add_type4(self, context)
    
                add_type5(self, context)
    
            if self.edit_mode:
                bpy.ops.object.mode_set(mode = 'EDIT')
            else:
                bpy.ops.object.mode_set(mode = 'OBJECT')
    
    def menu_funcs(self, context):
    
        bl_label = "Bevel/Taper"
    
    
        if context.view_layer.objects.active:
            if context.view_layer.objects.active.type == "CURVE":
                layout.operator("curve.bevelcurve")
                layout.operator("curve.tapercurve")
                layout.separator()
    
    # Register
    classes = [
        add_bevelcurve,
        add_tapercurve
    ]
    
    def register():
    
        from bpy.utils import register_class
        for cls in classes:
            register_class(cls)
    
        bpy.types.VIEW3D_MT_object_context_menu.prepend(menu_funcs)
    
    def unregister():
    
        from bpy.utils import unregister_class
        for cls in reversed(classes):
            unregister_class(cls)
    
        bpy.types.VIEW3D_MT_object_context_menu.remove(menu_funcs)
    
    if __name__ == "__main__":
        register()