1 # SPDX-FileCopyrightText: 2012-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 # Author: Anthony D'Agostino
8 from mathutils
import Vector
9 from math
import sin
, cos
, pi
10 from bpy
.props
import (
15 from bpy_extras
import object_utils
18 def create_mesh_object(context
, verts
, edges
, faces
, name
):
20 mesh
= bpy
.data
.meshes
.new(name
)
21 # Make a mesh from a list of verts/edges/faces.
22 mesh
.from_pydata(verts
, edges
, faces
)
23 # Update mesh geometry after adding stuff.
25 from bpy_extras
import object_utils
26 return object_utils
.object_data_add(context
, mesh
, operator
=None)
29 # ========================
30 # === Torus Knot Block ===
31 # ========================
34 x
= cos(t
) - 2 * cos(2 * t
)
35 y
= sin(t
) + 2 * sin(2 * t
)
37 return Vector([x
, y
, z
])
41 x
= 10 * (cos(t
) + cos(3 * t
)) + cos(2 * t
) + cos(4 * t
)
42 y
= 6 * sin(t
) + 10 * sin(3 * t
)
43 z
= 4 * sin(3 * t
) * sin(5 * t
/ 2) + 4 * sin(4 * t
) - 2 * sin(6 * t
)
44 return Vector([x
, y
, z
]) * 0.2
48 x
= 2.5 * cos(t
+ pi
) / 3 + 2 * cos(3 * t
)
49 y
= 2.5 * sin(t
) / 3 + 2 * sin(3 * t
)
50 z
= 1.5 * sin(4 * t
) + sin(2 * t
) / 3
51 return Vector([x
, y
, z
])
54 def make_verts(ures
, vres
, r2
, knotfunc
):
57 t1
= (i
+ 0) * 2 * pi
/ ures
58 t2
= (i
+ 1) * 2 * pi
/ ures
59 a
= knotfunc(t1
) # curr point
60 b
= knotfunc(t2
) # next point
61 a
, b
= map(Vector
, (a
, b
))
70 l
= (cos(k
), 0.0, sin(k
))
82 def make_faces(ures
, vres
):
84 for u
in range(0, ures
):
85 for v
in range(0, vres
):
87 p2
= v
+ ((u
+ 1) % ures
) * vres
88 p4
= (v
+ 1) % vres
+ u
* vres
89 p3
= (v
+ 1) % vres
+ ((u
+ 1) % ures
) * vres
90 faces
.append([p4
, p3
, p2
, p1
])
94 def make_knot(knotidx
, ures
):
96 knotfunc
= knots
[knotidx
- 1]
99 verts
= make_verts(ures
, vres
, r2
, knotfunc
)
100 faces
= make_faces(ures
, vres
)
101 return (verts
, faces
)
104 class AddTorusKnot(bpy
.types
.Operator
, object_utils
.AddObjectHelper
):
105 bl_idname
= "mesh.primitive_torusknot_add"
106 bl_label
= "Add Torus Knot"
107 bl_description
= "Construct a torus knot mesh"
108 bl_options
= {"REGISTER", "UNDO"}
110 TorusKnot
: BoolProperty(name
= "TorusKnot",
112 description
= "TorusKnot")
113 change
: BoolProperty(name
= "Change",
115 description
= "change TorusKnot")
117 resolution
: IntProperty(
119 description
="Resolution of the Torus Knot",
123 objecttype
: IntProperty(
125 description
="Type of Knot",
130 def draw(self
, context
):
133 layout
.prop(self
, 'resolution', expand
=True)
134 layout
.prop(self
, 'objecttype', expand
=True)
136 if self
.change
== False:
137 col
= layout
.column(align
=True)
138 col
.prop(self
, 'align', expand
=True)
139 col
= layout
.column(align
=True)
140 col
.prop(self
, 'location', expand
=True)
141 col
= layout
.column(align
=True)
142 col
.prop(self
, 'rotation', expand
=True)
144 def execute(self
, context
):
145 # turn off 'Enter Edit Mode'
146 use_enter_edit_mode
= bpy
.context
.preferences
.edit
.use_enter_edit_mode
147 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= False
149 if bpy
.context
.mode
== "OBJECT":
150 if context
.selected_objects
!= [] and context
.active_object
and \
151 (context
.active_object
.data
is not None) and ('TorusKnot' in context
.active_object
.data
.keys()) and \
152 (self
.change
== True):
153 obj
= context
.active_object
155 oldmeshname
= obj
.data
.name
156 verts
, faces
= make_knot(self
.objecttype
, self
.resolution
)
157 mesh
= bpy
.data
.meshes
.new('TorusKnot')
158 mesh
.from_pydata(verts
, [], faces
)
160 for material
in oldmesh
.materials
:
161 obj
.data
.materials
.append(material
)
162 bpy
.data
.meshes
.remove(oldmesh
)
163 obj
.data
.name
= oldmeshname
165 verts
, faces
= make_knot(self
.objecttype
, self
.resolution
)
166 mesh
= bpy
.data
.meshes
.new('TorusKnot')
167 mesh
.from_pydata(verts
, [], faces
)
168 obj
= object_utils
.object_data_add(context
, mesh
, operator
=self
)
170 obj
.data
["TorusKnot"] = True
171 obj
.data
["change"] = False
172 for prm
in TorusKnotParameters():
173 obj
.data
[prm
] = getattr(self
, prm
)
175 if bpy
.context
.mode
== "EDIT_MESH":
176 active_object
= context
.active_object
177 name_active_object
= active_object
.name
178 bpy
.ops
.object.mode_set(mode
='OBJECT')
179 verts
, faces
= make_knot(self
.objecttype
, self
.resolution
)
180 mesh
= bpy
.data
.meshes
.new('TorusKnot')
181 mesh
.from_pydata(verts
, [], faces
)
182 obj
= object_utils
.object_data_add(context
, mesh
, operator
=self
)
184 active_object
.select_set(True)
185 bpy
.context
.view_layer
.objects
.active
= active_object
186 bpy
.ops
.object.join()
187 context
.active_object
.name
= name_active_object
188 bpy
.ops
.object.mode_set(mode
='EDIT')
190 if use_enter_edit_mode
:
191 bpy
.ops
.object.mode_set(mode
= 'EDIT')
193 # restore pre operator state
194 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= use_enter_edit_mode
198 def TorusKnotParameters():
199 TorusKnotParameters
= [
203 return TorusKnotParameters