Import_3ds: Improved distance cue node setup
[blender-addons.git] / add_mesh_extra_objects / add_mesh_torusknot.py
blob8edf7035eb7e805f90dd03f5f347aadf4bda06de
1 # SPDX-FileCopyrightText: 2012-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 # Author: Anthony D'Agostino
7 import bpy
8 from mathutils import Vector
9 from math import sin, cos, pi
10 from bpy.props import (
11 BoolProperty,
12 IntProperty,
13 StringProperty,
15 from bpy_extras import object_utils
18 def create_mesh_object(context, verts, edges, faces, name):
19 # Create new mesh
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.
24 mesh.update()
25 from bpy_extras import object_utils
26 return object_utils.object_data_add(context, mesh, operator=None)
29 # ========================
30 # === Torus Knot Block ===
31 # ========================
33 def k1(t):
34 x = cos(t) - 2 * cos(2 * t)
35 y = sin(t) + 2 * sin(2 * t)
36 z = sin(3 * t)
37 return Vector([x, y, z])
40 def k2(t):
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
47 def k3(t):
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):
55 verts = []
56 for i in range(ures):
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))
62 e = a - b
63 f = a + b
64 g = e.cross(f)
65 h = e.cross(g)
66 g.normalize()
67 h.normalize()
68 for j in range(vres):
69 k = j * 2 * pi / vres
70 l = (cos(k), 0.0, sin(k))
71 l = Vector(l)
72 m = l * r2
73 x, y, z = m
74 n = h * x
75 o = g * z
76 p = n + o
77 q = a + p
78 verts.append(q)
79 return verts
82 def make_faces(ures, vres):
83 faces = []
84 for u in range(0, ures):
85 for v in range(0, vres):
86 p1 = v + u * 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])
91 return faces
94 def make_knot(knotidx, ures):
95 knots = [k1, k2, k3]
96 knotfunc = knots[knotidx - 1]
97 vres = ures // 10
98 r2 = 0.5
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",
111 default = True,
112 description = "TorusKnot")
113 change : BoolProperty(name = "Change",
114 default = False,
115 description = "change TorusKnot")
117 resolution: IntProperty(
118 name="Resolution",
119 description="Resolution of the Torus Knot",
120 default=80,
121 min=30, max=256
123 objecttype: IntProperty(
124 name="Knot Type",
125 description="Type of Knot",
126 default=1,
127 min=1, max=3
130 def draw(self, context):
131 layout = self.layout
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
154 oldmesh = obj.data
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)
159 obj.data = mesh
160 for material in oldmesh.materials:
161 obj.data.materials.append(material)
162 bpy.data.meshes.remove(oldmesh)
163 obj.data.name = oldmeshname
164 else:
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)
183 obj.select_set(True)
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
196 return {'FINISHED'}
198 def TorusKnotParameters():
199 TorusKnotParameters = [
200 "resolution",
201 "objecttype",
203 return TorusKnotParameters