Skip to content
Snippets Groups Projects
add_curve_simple.py 58.8 KiB
Newer Older
  • Learn to ignore specific revisions
  •             col.label(text=self.Simple_Type + " Options")
                box = layout.box()
                box.prop(self, 'Simple_a')
                box.prop(self, 'Simple_b')
                box.prop(self, 'Simple_h')
                box.prop(self, 'Simple_center')
                g = hypot(self.Simple_h, (self.Simple_a - self.Simple_b) / 2)
                l = self.Simple_a + self.Simple_b + g * 2
                s = (abs(self.Simple_a) + abs(self.Simple_b)) / 2 * self.Simple_h
    
            row = layout.row()
            row.prop(self, 'shape', expand=True)
            box = layout.box()
            box.label("Location:")
            box.prop(self, 'Simple_startlocation')
            box = layout.box()
            box.label("Rotation:")
            box.prop(self, 'Simple_rotation_euler')
            if l != 0:
                l_str = str(round(l, 4))
                row = layout.row()
                row.label("Length: " + l_str)
            if s != 0:
                s_str = str(round(s, 4))
                row = layout.row()
                row.label("Area: " + s_str)
    
        ##### POLL #####
        @classmethod
        def poll(cls, context):
    
            return context.scene is not None
    
    
        ##### EXECUTE #####
        def execute(self, context):
            if self.Simple_Change:
                SimpleDelete(self.Simple_Delete)
    
            # go to object mode
            if bpy.ops.object.mode_set.poll():
                bpy.ops.object.mode_set(mode='OBJECT')
    
            # turn off undo
            undo = bpy.context.user_preferences.edit.use_global_undo
            bpy.context.user_preferences.edit.use_global_undo = False
    
            # main function
            self.align_matrix = align_matrix(context, self.Simple_startlocation)
            main(context, self, self.align_matrix)
    
            # restore pre operator undo state
            bpy.context.user_preferences.edit.use_global_undo = undo
    
            return {'FINISHED'}
    
        ##### INVOKE #####
        def invoke(self, context, event):
            # store creation_matrix
            if self.Simple_Change:
                bpy.context.scene.cursor_location = self.Simple_startlocation
            else:
                self.Simple_startlocation = bpy.context.scene.cursor_location
    
            self.align_matrix = align_matrix(context, self.Simple_startlocation)
            self.execute(context)
    
            return {'FINISHED'}
    
    # ------------------------------------------------------------
    # Fillet
    
    
    class BezierPointsFillet(bpy.types.Operator):
        ''''''
        bl_idname = "curve.bezier_points_fillet"
        bl_label = "Bezier points fillet"
        bl_options = {'REGISTER', 'UNDO'}
        bl_description = "bezier points fillet"
    
        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)
    
        ##### DRAW #####
        def draw(self, context):
            layout = self.layout
    
            # general options
            col = layout.column()
            col.prop(self, 'Fillet_radius')
            col.prop(self, 'Fillet_Type', expand=True)
    
        ##### POLL #####
        @classmethod
        def poll(cls, context):
    
            return context.scene is not None
    
    
        ##### EXECUTE #####
        def execute(self, context):
            # go to object mode
            if bpy.ops.object.mode_set.poll():
                bpy.ops.object.mode_set(mode='OBJECT')
                bpy.ops.object.mode_set(mode='EDIT')
    
            # turn off undo
            undo = bpy.context.user_preferences.edit.use_global_undo
            bpy.context.user_preferences.edit.use_global_undo = False
    
            # main function
            spline = bpy.context.object.data.splines.active
            selected = [p for p in spline.bezier_points if p.select_control_point]
    
            bpy.ops.curve.handle_type_set(type='VECTOR')
            n = 0
            ii = []
            for p in spline.bezier_points:
                if p.select_control_point:
                    ii.append(n)
                    n += 1
                else:
                    n += 1
    
            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'
    
            bpy.ops.curve.select_all(action='SELECT')
            bpy.ops.curve.spline_type_set(type='BEZIER')
    
            # restore pre operator undo state
            bpy.context.user_preferences.edit.use_global_undo = undo
    
            return {'FINISHED'}
    
        ##### INVOKE #####
        def invoke(self, context, event):
            self.execute(context)
    
            return {'FINISHED'}
    
    
    def subdivide_cubic_bezier(p1, p2, p3, p4, t):
        p12 = (p2 - p1) * t + p1
        p23 = (p3 - p2) * t + p2
        p34 = (p4 - p3) * t + p3
        p123 = (p23 - p12) * t + p12
        p234 = (p34 - p23) * t + p23
        p1234 = (p234 - p123) * t + p123
        return [p12, p123, p1234, p234, p34]
    
    # ------------------------------------------------------------
    # BezierDivide Operator
    
    
    class BezierDivide(bpy.types.Operator):
        ''''''
        bl_idname = "curve.bezier_spline_divide"
        bl_label = "Bezier Divide (enters edit mode) for Fillet Curves"
        bl_options = {'REGISTER', 'UNDO'}
        bl_description = "bezier spline divide"
    
        # 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%)")
    
        ##### POLL #####
        @classmethod
        def poll(cls, context):
    
            return context.scene is not None
    
    
        ##### EXECUTE #####
        def execute(self, context):
            # go to object mode
            if bpy.ops.object.mode_set.poll():
                bpy.ops.object.mode_set(mode='OBJECT')
                bpy.ops.object.mode_set(mode='EDIT')
    
            # turn off undo
            undo = bpy.context.user_preferences.edit.use_global_undo
            bpy.context.user_preferences.edit.use_global_undo = False
    
            # main function
            spline = bpy.context.object.data.splines.active
            vertex = []
            selected_all = [p for p in spline.bezier_points if p.select_control_point]
            h = subdivide_cubic_bezier(selected_all[0].co, selected_all[0].handle_right, selected_all[1].handle_left, selected_all[1].co, self.Bezier_t / 100)
    
            selected_all[0].handle_right_type = 'FREE'
            selected_all[0].handle_left_type = 'FREE'
            selected_all[1].handle_right_type = 'FREE'
            selected_all[1].handle_left_type = 'FREE'
            bpy.ops.curve.subdivide(1)
            selected_all = [p for p in spline.bezier_points if p.select_control_point]
    
            selected_all[0].handle_right = h[0]
            selected_all[1].co = h[2]
            selected_all[1].handle_left = h[1]
            selected_all[1].handle_right = h[3]
            selected_all[2].handle_left = h[4]
    
            # restore pre operator undo state
            bpy.context.user_preferences.edit.use_global_undo = undo
    
            return {'FINISHED'}
    
        ##### INVOKE #####
        def invoke(self, context, event):
            self.execute(context)
    
            return {'FINISHED'}
    
    # ------------------------------------------------------------
    # Simple change panel
    
    
    class SimplePanel(bpy.types.Panel):
    
        bl_label = "Simple change"
        bl_space_type = "VIEW_3D"
        bl_region_type = "TOOLS"
        bl_options = {'DEFAULT_CLOSED'}
        bl_category = "Tools"
    
        ##### POLL #####
        @classmethod
        def poll(cls, context):
            if not context.active_object:
                pass
            elif context.object.Simple == True:
                return (context.object)
    
        ##### DRAW #####
        def draw(self, context):
            if context.object.Simple == True:
    
                layout = self.layout
    
                obj = context.object
                row = layout.row()
                simple_change = row.operator("curve.simple", text='Change')
                simple_change.Simple_Change = True
                simple_change.Simple_Delete = obj.name
                simple_change.Simple_Type = obj.Simple_Type
                simple_change.Simple_startlocation = obj.location
                simple_change.Simple_endlocation = obj.Simple_endlocation
                simple_change.Simple_a = obj.Simple_a
                simple_change.Simple_b = obj.Simple_b
                simple_change.Simple_h = obj.Simple_h
                simple_change.Simple_angle = obj.Simple_angle
                simple_change.Simple_startangle = obj.Simple_startangle
                simple_change.Simple_endangle = obj.Simple_endangle
                simple_change.Simple_rotation_euler = obj.rotation_euler
                simple_change.Simple_sides = obj.Simple_sides
                simple_change.Simple_radius = obj.Simple_radius
                simple_change.Simple_center = obj.Simple_center
                simple_change.Simple_width = obj.Simple_width
                simple_change.Simple_length = obj.Simple_length
                simple_change.Simple_rounded = obj.Simple_rounded
    
    # ------------------------------------------------------------
    # Fillet tools panel
    
    
    class SimpleEdit(bpy.types.Operator):
    
        """Curve Simple"""
        bl_idname = "object._simple_edit"
        bl_label = "Create Curves"
        bl_options = {'REGISTER', 'UNDO'}
        bl_description = "Subdivide & Fillet Curves"
    
        ##### POLL #####
        @classmethod
        def poll(cls, context):
            vertex = []
            nselected = []
            n = 0
            obj = context.active_object
    
            if obj is not None:
    
                if obj.type == 'CURVE':
                    for i in obj.data.splines:
                        for j in i.bezier_points:
                            n += 1
                            if j.select_control_point:
                                nselected.append(n)
                                vertex.append(obj.matrix_world * j.co)
    
                if len(vertex) > 0 and n > 2:
                    return (context.active_object)
                if len(vertex) == 2 and abs(nselected[0] - nselected[1]) == 1:
                    return (context.active_object)
    
            selected = 0
            for obj in context.selected_objects:
                if obj.type == 'CURVE':
                    selected += 1
    
            if selected >= 2:
                return (context.selected_objects)
    
        ##### DRAW #####
        def draw(self, context):
            vertex = []
            selected = []
            n = 0
            obj = context.active_object
    
            if obj is not None:
    
                if obj.type == 'CURVE':
                    for i in obj.data.splines:
                        for j in i.bezier_points:
                            n += 1
                            if j.select_control_point:
                                selected.append(n)
                                vertex.append(obj.matrix_world * j.co)
    
                if len(vertex) > 0 and n > 2:
                    layout = self.layout
                    row = layout.row()
                    simple_edit = row.operator("curve.bezier_points_fillet", text='Fillet')
                if len(vertex) == 2 and abs(selected[0] - selected[1]) == 1:
                    layout = self.layout
                    row = layout.row()
                    simple_divide = row.operator("curve.bezier_spline_divide", text='Divide')
    
    # ------------------------------------------------------------
    # location update
    
    
    def StartLocationUpdate(self, context):
    
        bpy.context.scene.cursor_location = self.Simple_startlocation
    
        return
    
    # ------------------------------------------------------------
    # Add properties to objects
    
    
    def SimpleVariables():
    
        bpy.types.Object.Simple = bpy.props.BoolProperty()
        bpy.types.Object.Simple_Change = bpy.props.BoolProperty()
        # general properties
        Types = [('Point', 'Point', 'Point'),
                 ('Line', 'Line', 'Line'),
                 ('Distance', 'Distance', 'Distance'),
                 ('Angle', 'Angle', 'Angle'),
                 ('Circle', 'Circle', 'Circle'),
                 ('Ellipse', 'Ellipse', 'Ellipse'),
                 ('Arc', 'Arc', 'Arc'),
                 ('Sector', 'Sector', 'Sector'),
                 ('Segment', 'Segment', 'Segment'),
                 ('Rectangle', 'Rectangle', 'Rectangle'),
                 ('Rhomb', 'Rhomb', 'Rhomb'),
                 ('Polygon', 'Polygon', 'Polygon'),
                 ('Polygon_ab', 'Polygon_ab', 'Polygon_ab'),
                 ('Trapezoid', 'Trapezoid', 'Trapezoid')]
        bpy.types.Object.Simple_Type = bpy.props.EnumProperty(name="Type",
                                                              description="Form of Curve to create",
                                                              items=Types)
    
        # Line properties
        bpy.types.Object.Simple_startlocation = bpy.props.FloatVectorProperty(name="Start location",
                                                                              description="Start location",
                                                                              default=(0.0, 0.0, 0.0),
                                                                              subtype='TRANSLATION',
                                                                              update=StartLocationUpdate)
        bpy.types.Object.Simple_endlocation = bpy.props.FloatVectorProperty(name="End location",
                                                                            description="End location",
                                                                            default=(2.0, 2.0, 2.0),
                                                                            subtype='TRANSLATION')
        bpy.types.Object.Simple_rotation_euler = bpy.props.FloatVectorProperty(name="Rotation",
                                                                               description="Rotation",
                                                                               default=(0.0, 0.0, 0.0),
                                                                               subtype='EULER')
    
        # Trapezoid properties
        bpy.types.Object.Simple_a = bpy.props.FloatProperty(name="a",
                                                            default=2.0,
                                                            min=0.0, soft_min=0.0,
                                                            unit='LENGTH',
                                                            description="a")
        bpy.types.Object.Simple_b = bpy.props.FloatProperty(name="b",
                                                            default=1.0,
                                                            min=0.0, soft_min=0.0,
                                                            unit='LENGTH',
                                                            description="b")
        bpy.types.Object.Simple_h = bpy.props.FloatProperty(name="h",
                                                            default=1.0,
                                                            unit='LENGTH',
                                                            description="h")
    
        bpy.types.Object.Simple_angle = bpy.props.FloatProperty(name="Angle",
                                                                default=45.0,
                                                                description="Angle")
        bpy.types.Object.Simple_startangle = bpy.props.FloatProperty(name="Start angle",
                                                                     default=0.0,
                                                                     min=-360.0, soft_min=-360.0,
                                                                     max=360.0, soft_max=360.0,
                                                                     description="Start angle")
        bpy.types.Object.Simple_endangle = bpy.props.FloatProperty(name="End angle",
                                                                   default=45.0,
                                                                   min=-360.0, soft_min=-360.0,
                                                                   max=360.0, soft_max=360.0,
                                                                   description="End angle")
    
        bpy.types.Object.Simple_sides = bpy.props.IntProperty(name="sides",
                                                              default=3,
                                                              min=3, soft_min=3,
                                                              description="sides")
    
        bpy.types.Object.Simple_radius = bpy.props.FloatProperty(name="radius",
                                                                 default=1.0,
                                                                 min=0.0, soft_min=0.0,
                                                                 unit='LENGTH',
                                                                 description="radius")
    
        bpy.types.Object.Simple_center = bpy.props.BoolProperty(name="Length center",
                                                                default=True,
                                                                description="Length center")
    
        # Rectangle properties
        bpy.types.Object.Simple_width = bpy.props.FloatProperty(name="Width",
                                                                default=2.0,
                                                                min=0.0, soft_min=0.0,
                                                                unit='LENGTH',
                                                                description="Width")
        bpy.types.Object.Simple_length = bpy.props.FloatProperty(name="Length",
                                                                 default=2.0,
                                                                 min=0.0, soft_min=0.0,
                                                                 unit='LENGTH',
                                                                 description="Length")
        bpy.types.Object.Simple_rounded = bpy.props.FloatProperty(name="Rounded",
                                                                  default=0.0,
                                                                  unit='LENGTH',
                                                                  description="Rounded")
    
    ################################################################################
    ##### REGISTER #####
    
    
    class INFO_MT_simple_menu(bpy.types.Menu):
        # Define the "Extras" menu
        bl_idname = "INFO_MT_simple_menu"
        bl_label = "2D Objects"
    
        def draw(self, context):
            self.layout.operator_context = 'INVOKE_REGION_WIN'
    
            oper2 = self.layout.operator(Simple.bl_idname, text="Point", icon="MOD_CURVE")
            oper2.Simple_Change = False
            oper2.Simple_Type = "Point"
    
            oper3 = self.layout.operator(Simple.bl_idname, text="Line", icon="MOD_CURVE")
            oper3.Simple_Change = False
            oper3.Simple_Type = "Line"
    
            oper4 = self.layout.operator(Simple.bl_idname, text="Distance", icon="MOD_CURVE")
            oper4.Simple_Change = False
            oper4.Simple_Type = "Distance"
    
            oper5 = self.layout.operator(Simple.bl_idname, text="Angle", icon="MOD_CURVE")
            oper5.Simple_Change = False
            oper5.Simple_Type = "Angle"
    
            oper6 = self.layout.operator(Simple.bl_idname, text="Circle", icon="MOD_CURVE")
            oper6.Simple_Change = False
            oper6.Simple_Type = "Circle"
    
            oper7 = self.layout.operator(Simple.bl_idname, text="Ellipse", icon="MOD_CURVE")
            oper7.Simple_Change = False
            oper7.Simple_Type = "Ellipse"
    
            oper8 = self.layout.operator(Simple.bl_idname, text="Arc", icon="MOD_CURVE")
            oper8.Simple_Change = False
            oper8.Simple_Type = "Arc"
    
            oper9 = self.layout.operator(Simple.bl_idname, text="Sector", icon="MOD_CURVE")
            oper9.Simple_Change = False
            oper9.Simple_Type = "Sector"
    
            oper10 = self.layout.operator(Simple.bl_idname, text="Segment", icon="MOD_CURVE")
            oper10.Simple_Change = False
            oper10.Simple_Type = "Segment"
    
            oper11 = self.layout.operator(Simple.bl_idname, text="Rectangle", icon="MOD_CURVE")
            oper11.Simple_Change = False
            oper11.Simple_Type = "Rectangle"
    
            oper12 = self.layout.operator(Simple.bl_idname, text="Rhomb", icon="MOD_CURVE")
            oper12.Simple_Change = False
            oper12.Simple_Type = "Rhomb"
    
            oper13 = self.layout.operator(Simple.bl_idname, text="Polygon", icon="MOD_CURVE")
            oper13.Simple_Change = False
            oper13.Simple_Type = "Polygon"
    
            oper14 = self.layout.operator(Simple.bl_idname, text="Polygon_ab", icon="MOD_CURVE")
            oper14.Simple_Change = False
            oper14.Simple_Type = "Polygon_ab"
    
            oper15 = self.layout.operator(Simple.bl_idname, text="Trapezoid", icon="MOD_CURVE")
            oper15.Simple_Change = False
            oper15.Simple_Type = "Trapezoid"
    
    
    def Simple_button(self, context):
        layout = self.layout
        layout.separator()
        oper11 = self.layout.operator(Simple.bl_idname, text="Rectangle", icon="MOD_CURVE")
        oper11.Simple_Change = False
        oper11.Simple_Type = "Rectangle"
    
        self.layout.menu("INFO_MT_simple_menu", icon="MOD_CURVE")
    
    
    def register():
        bpy.utils.register_class(Simple)
        bpy.utils.register_class(BezierPointsFillet)
        bpy.utils.register_class(BezierDivide)
        bpy.utils.register_class(SimplePanel)
        bpy.utils.register_class(SimpleEdit)
        bpy.utils.register_class(INFO_MT_simple_menu)
    
        bpy.types.INFO_MT_curve_add.append(Simple_button)
    
        SimpleVariables()
    
    
    def unregister():
        bpy.utils.unregister_class(Simple)
        bpy.utils.unregister_class(BezierPointsFillet)
        bpy.utils.unregister_class(BezierDivide)
        bpy.utils.unregister_class(SimplePanel)
        bpy.utils.unregister_class(SimpleEdit)
        bpy.utils.unregister_class(INFO_MT_simple_menu)
    
        bpy.types.INFO_MT_curve_add.remove(Simple_button)
    
    if __name__ == "__main__":
        register()