1 # SPDX-License-Identifier: GPL-2.0-or-later
3 # Author: Anthony D'Agostino
6 from mathutils
import Vector
7 from math
import sin
, cos
, pi
8 from bpy
.props
import (
13 from bpy_extras
import object_utils
16 def create_mesh_object(context
, verts
, edges
, faces
, name
):
18 mesh
= bpy
.data
.meshes
.new(name
)
19 # Make a mesh from a list of verts/edges/faces.
20 mesh
.from_pydata(verts
, edges
, faces
)
21 # Update mesh geometry after adding stuff.
23 from bpy_extras
import object_utils
24 return object_utils
.object_data_add(context
, mesh
, operator
=None)
27 # ========================
28 # === Torus Knot Block ===
29 # ========================
32 x
= cos(t
) - 2 * cos(2 * t
)
33 y
= sin(t
) + 2 * sin(2 * t
)
35 return Vector([x
, y
, z
])
39 x
= 10 * (cos(t
) + cos(3 * t
)) + cos(2 * t
) + cos(4 * t
)
40 y
= 6 * sin(t
) + 10 * sin(3 * t
)
41 z
= 4 * sin(3 * t
) * sin(5 * t
/ 2) + 4 * sin(4 * t
) - 2 * sin(6 * t
)
42 return Vector([x
, y
, z
]) * 0.2
46 x
= 2.5 * cos(t
+ pi
) / 3 + 2 * cos(3 * t
)
47 y
= 2.5 * sin(t
) / 3 + 2 * sin(3 * t
)
48 z
= 1.5 * sin(4 * t
) + sin(2 * t
) / 3
49 return Vector([x
, y
, z
])
52 def make_verts(ures
, vres
, r2
, knotfunc
):
55 t1
= (i
+ 0) * 2 * pi
/ ures
56 t2
= (i
+ 1) * 2 * pi
/ ures
57 a
= knotfunc(t1
) # curr point
58 b
= knotfunc(t2
) # next point
59 a
, b
= map(Vector
, (a
, b
))
68 l
= (cos(k
), 0.0, sin(k
))
80 def make_faces(ures
, vres
):
82 for u
in range(0, ures
):
83 for v
in range(0, vres
):
85 p2
= v
+ ((u
+ 1) % ures
) * vres
86 p4
= (v
+ 1) % vres
+ u
* vres
87 p3
= (v
+ 1) % vres
+ ((u
+ 1) % ures
) * vres
88 faces
.append([p4
, p3
, p2
, p1
])
92 def make_knot(knotidx
, ures
):
94 knotfunc
= knots
[knotidx
- 1]
97 verts
= make_verts(ures
, vres
, r2
, knotfunc
)
98 faces
= make_faces(ures
, vres
)
102 class AddTorusKnot(bpy
.types
.Operator
, object_utils
.AddObjectHelper
):
103 bl_idname
= "mesh.primitive_torusknot_add"
104 bl_label
= "Add Torus Knot"
105 bl_description
= "Construct a torus knot mesh"
106 bl_options
= {"REGISTER", "UNDO"}
108 TorusKnot
: BoolProperty(name
= "TorusKnot",
110 description
= "TorusKnot")
111 change
: BoolProperty(name
= "Change",
113 description
= "change TorusKnot")
115 resolution
: IntProperty(
117 description
="Resolution of the Torus Knot",
121 objecttype
: IntProperty(
123 description
="Type of Knot",
128 def draw(self
, context
):
131 layout
.prop(self
, 'resolution', expand
=True)
132 layout
.prop(self
, 'objecttype', expand
=True)
134 if self
.change
== False:
135 col
= layout
.column(align
=True)
136 col
.prop(self
, 'align', expand
=True)
137 col
= layout
.column(align
=True)
138 col
.prop(self
, 'location', expand
=True)
139 col
= layout
.column(align
=True)
140 col
.prop(self
, 'rotation', expand
=True)
142 def execute(self
, context
):
143 # turn off 'Enter Edit Mode'
144 use_enter_edit_mode
= bpy
.context
.preferences
.edit
.use_enter_edit_mode
145 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= False
147 if bpy
.context
.mode
== "OBJECT":
148 if context
.selected_objects
!= [] and context
.active_object
and \
149 (context
.active_object
.data
is not None) and ('TorusKnot' in context
.active_object
.data
.keys()) and \
150 (self
.change
== True):
151 obj
= context
.active_object
153 oldmeshname
= obj
.data
.name
154 verts
, faces
= make_knot(self
.objecttype
, self
.resolution
)
155 mesh
= bpy
.data
.meshes
.new('TorusKnot')
156 mesh
.from_pydata(verts
, [], faces
)
158 for material
in oldmesh
.materials
:
159 obj
.data
.materials
.append(material
)
160 bpy
.data
.meshes
.remove(oldmesh
)
161 obj
.data
.name
= oldmeshname
163 verts
, faces
= make_knot(self
.objecttype
, self
.resolution
)
164 mesh
= bpy
.data
.meshes
.new('TorusKnot')
165 mesh
.from_pydata(verts
, [], faces
)
166 obj
= object_utils
.object_data_add(context
, mesh
, operator
=self
)
168 obj
.data
["TorusKnot"] = True
169 obj
.data
["change"] = False
170 for prm
in TorusKnotParameters():
171 obj
.data
[prm
] = getattr(self
, prm
)
173 if bpy
.context
.mode
== "EDIT_MESH":
174 active_object
= context
.active_object
175 name_active_object
= active_object
.name
176 bpy
.ops
.object.mode_set(mode
='OBJECT')
177 verts
, faces
= make_knot(self
.objecttype
, self
.resolution
)
178 mesh
= bpy
.data
.meshes
.new('TorusKnot')
179 mesh
.from_pydata(verts
, [], faces
)
180 obj
= object_utils
.object_data_add(context
, mesh
, operator
=self
)
182 active_object
.select_set(True)
183 bpy
.context
.view_layer
.objects
.active
= active_object
184 bpy
.ops
.object.join()
185 context
.active_object
.name
= name_active_object
186 bpy
.ops
.object.mode_set(mode
='EDIT')
188 if use_enter_edit_mode
:
189 bpy
.ops
.object.mode_set(mode
= 'EDIT')
191 # restore pre operator state
192 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= use_enter_edit_mode
196 def TorusKnotParameters():
197 TorusKnotParameters
= [
201 return TorusKnotParameters