Skip to content
Snippets Groups Projects
add_mesh_torusknot.py 6.12 KiB
Newer Older
  • Learn to ignore specific revisions
  • # GPL #  Author, Anthony D'Agostino
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    
    import bpy
    from mathutils import Vector
    from math import sin, cos, pi
    
    from bpy.props import (
            BoolProperty,
            IntProperty,
            StringProperty,
            )
    from bpy_extras import object_utils
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    def create_mesh_object(context, verts, edges, faces, name):
        # Create new mesh
        mesh = bpy.data.meshes.new(name)
        # Make a mesh from a list of verts/edges/faces.
        mesh.from_pydata(verts, edges, faces)
        # Update mesh geometry after adding stuff.
        mesh.update()
        from bpy_extras import object_utils
        return object_utils.object_data_add(context, mesh, operator=None)
    
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    # ========================
    # === Torus Knot Block ===
    # ========================
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    def k1(t):
    
        x = cos(t) - 2 * cos(2 * t)
        y = sin(t) + 2 * sin(2 * t)
        z = sin(3 * t)
        return Vector([x, y, z])
    
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    def k2(t):
    
        x = 10 * (cos(t) + cos(3 * t)) + cos(2 * t) + cos(4 * t)
        y = 6 * sin(t) + 10 * sin(3 * t)
        z = 4 * sin(3 * t) * sin(5 * t / 2) + 4 * sin(4 * t) - 2 * sin(6 * t)
        return Vector([x, y, z]) * 0.2
    
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    def k3(t):
    
        x = 2.5 * cos(t + pi) / 3 + 2 * cos(3 * t)
        y = 2.5 * sin(t) / 3 + 2 * sin(3 * t)
        z = 1.5 * sin(4 * t) + sin(2 * t) / 3
        return Vector([x, y, z])
    
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    def make_verts(ures, vres, r2, knotfunc):
    
        verts = []
        for i in range(ures):
            t1 = (i + 0) * 2 * pi / ures
            t2 = (i + 1) * 2 * pi / ures
            a = knotfunc(t1)        # curr point
            b = knotfunc(t2)        # next point
            a, b = map(Vector, (a, b))
            e = a - b
            f = a + b
            g = e.cross(f)
            h = e.cross(g)
            g.normalize()
            h.normalize()
            for j in range(vres):
                k = j * 2 * pi / vres
                l = (cos(k), 0.0, sin(k))
                l = Vector(l)
                m = l * r2
                x, y, z = m
                n = h * x
                o = g * z
                p = n + o
                q = a + p
                verts.append(q)
        return verts
    
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    def make_faces(ures, vres):
    
        faces = []
        for u in range(0, ures):
            for v in range(0, vres):
                p1 = v + u * vres
                p2 = v + ((u + 1) % ures) * vres
                p4 = (v + 1) % vres + u * vres
                p3 = (v + 1) % vres + ((u + 1) % ures) * vres
                faces.append([p4, p3, p2, p1])
        return faces
    
    
    Brendon Murphy's avatar
    Brendon Murphy committed
    
    def make_knot(knotidx, ures):
    
        knots = [k1, k2, k3]
        knotfunc = knots[knotidx - 1]
        vres = ures // 10
        r2 = 0.5
        verts = make_verts(ures, vres, r2, knotfunc)
        faces = make_faces(ures, vres)
        return (verts, faces)
    
    
    class AddTorusKnot(bpy.types.Operator, object_utils.AddObjectHelper):
    
        bl_idname = "mesh.primitive_torusknot_add"
        bl_label = "Add Torus Knot"
        bl_description = "Construct a torus knot mesh"
        bl_options = {"REGISTER", "UNDO"}
    
    
        TorusKnot : BoolProperty(name = "TorusKnot",
                    default = True,
                    description = "TorusKnot")
        change : BoolProperty(name = "Change",
                    default = False,
                    description = "change TorusKnot")
    
    
        resolution: IntProperty(
    
            name="Resolution",
            description="Resolution of the Torus Knot",
            default=80,
            min=30, max=256
            )
    
        objecttype: IntProperty(
    
            name="Knot Type",
            description="Type of Knot",
            default=1,
            min=1, max=3
            )
    
        def draw(self, context):
            layout = self.layout
    
            layout.prop(self, 'resolution', expand=True)
            layout.prop(self, 'objecttype', expand=True)
    
            if self.change == False:
                col = layout.column(align=True)
                col.prop(self, 'align', expand=True)
                col = layout.column(align=True)
                col.prop(self, 'location', expand=True)
                col = layout.column(align=True)
                col.prop(self, 'rotation', expand=True)
    
    
        def execute(self, context):
    
            # turn off 'Enter Edit Mode'
            use_enter_edit_mode = bpy.context.preferences.edit.use_enter_edit_mode
            bpy.context.preferences.edit.use_enter_edit_mode = False
    
    
            if bpy.context.mode == "OBJECT":
                if context.selected_objects != [] and context.active_object and \
                ('TorusKnot' in context.active_object.data.keys()) and (self.change == True):
                    obj = context.active_object
                    oldmesh = obj.data
                    oldmeshname = obj.data.name
                    verts, faces = make_knot(self.objecttype, self.resolution)
                    mesh = bpy.data.meshes.new('TorusKnot')
                    mesh.from_pydata(verts, [], faces)
                    obj.data = mesh
                    for material in oldmesh.materials:
                        obj.data.materials.append(material)
                    bpy.data.meshes.remove(oldmesh)
                    obj.data.name = oldmeshname
                else:
                    verts, faces = make_knot(self.objecttype, self.resolution)
                    mesh = bpy.data.meshes.new('TorusKnot')
                    mesh.from_pydata(verts, [], faces)
                    obj = object_utils.object_data_add(context, mesh, operator=self)
    
                obj.data["TorusKnot"] = True
                obj.data["change"] = False
                for prm in TorusKnotParameters():
                    obj.data[prm] = getattr(self, prm)
    
            if bpy.context.mode == "EDIT_MESH":
                active_object = context.active_object
                name_active_object = active_object.name
                bpy.ops.object.mode_set(mode='OBJECT')
                verts, faces = make_knot(self.objecttype, self.resolution)
                mesh = bpy.data.meshes.new('TorusKnot')
                mesh.from_pydata(verts, [], faces)
    
                obj = object_utils.object_data_add(context, mesh, operator=self)
    
                obj.select_set(True)
                active_object.select_set(True)
                bpy.ops.object.join()
                context.active_object.name = name_active_object
                bpy.ops.object.mode_set(mode='EDIT')
    
            if use_enter_edit_mode:
                bpy.ops.object.mode_set(mode = 'EDIT')
    
            # restore pre operator state
            bpy.context.preferences.edit.use_enter_edit_mode = use_enter_edit_mode
    
    
            return {'FINISHED'}
    
    
    def TorusKnotParameters():
        TorusKnotParameters = [
            "resolution",
            "objecttype",
            ]
        return TorusKnotParameters