Fix error in rigify property generation
[blender-addons.git] / add_mesh_extra_objects / add_mesh_supertoroid.py
blob8a87a289b51a556b81bff0647de7ec1fac09d19c
1 # GPL # "author": "DreamPainter"
3 import bpy
4 from bpy.props import (
5 FloatProperty,
6 BoolProperty,
7 IntProperty,
8 StringProperty,
10 from math import pi, cos, sin
11 from mathutils import Vector
12 from bpy_extras import object_utils
15 # A very simple "bridge" tool
17 def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False):
18 faces = []
20 if not vertIdx1 or not vertIdx2:
21 return None
23 if len(vertIdx1) < 2 and len(vertIdx2) < 2:
24 return None
26 fan = False
27 if (len(vertIdx1) != len(vertIdx2)):
28 if (len(vertIdx1) == 1 and len(vertIdx2) > 1):
29 fan = True
30 else:
31 return None
33 total = len(vertIdx2)
35 if closed:
36 # Bridge the start with the end.
37 if flipped:
38 face = [
39 vertIdx1[0],
40 vertIdx2[0],
41 vertIdx2[total - 1]]
42 if not fan:
43 face.append(vertIdx1[total - 1])
44 faces.append(face)
46 else:
47 face = [vertIdx2[0], vertIdx1[0]]
48 if not fan:
49 face.append(vertIdx1[total - 1])
50 face.append(vertIdx2[total - 1])
51 faces.append(face)
53 # Bridge the rest of the faces.
54 for num in range(total - 1):
55 if flipped:
56 if fan:
57 face = [vertIdx2[num], vertIdx1[0], vertIdx2[num + 1]]
58 else:
59 face = [vertIdx2[num], vertIdx1[num],
60 vertIdx1[num + 1], vertIdx2[num + 1]]
61 faces.append(face)
62 else:
63 if fan:
64 face = [vertIdx1[0], vertIdx2[num], vertIdx2[num + 1]]
65 else:
66 face = [vertIdx1[num], vertIdx2[num],
67 vertIdx2[num + 1], vertIdx1[num + 1]]
68 faces.append(face)
70 return faces
73 def power(a, b):
74 if a < 0:
75 return -((-a) ** b)
76 return a ** b
79 def supertoroid(R, r, u, v, n1, n2):
80 """
81 R = big radius
82 r = small radius
83 u = lateral segmentation
84 v = radial segmentation
85 n1 = value determines the shape of the torus
86 n2 = value determines the shape of the cross-section
87 """
88 # create the necessary constants
89 a = 2 * pi / u
90 b = 2 * pi / v
92 verts = []
93 faces = []
95 # create each cross-section by calculating each vector on the
96 # the wannabe circle
97 # x = (cos(theta) ** n1)*(R + r * (cos(phi) ** n2))
98 # y = (sin(theta) ** n1)*(R + r * (cos(phi) ** n2))
99 # z = (r * sin(phi) ** n2)
100 # with theta and phi rangeing from 0 to 2pi
102 for i in range(u):
103 s = power(sin(i * a), n1)
104 c = power(cos(i * a), n1)
105 for j in range(v):
106 c2 = R + r * power(cos(j * b), n2)
107 s2 = r * power(sin(j * b), n2)
108 verts.append(Vector((c * c2, s * c2, s2)))
110 # bridge the last circle with the previous circle
111 if i > 0: # but not for the first circle, 'cus there's no previous before the first
112 f = createFaces(range((i - 1) * v, i * v), range(i * v, (i + 1) * v), closed=True)
113 faces.extend(f)
114 # bridge the last circle with the first
115 f = createFaces(range((u - 1) * v, u * v), range(v), closed=True)
116 faces.extend(f)
118 return verts, faces
121 class add_supertoroid(bpy.types.Operator, object_utils.AddObjectHelper):
122 bl_idname = "mesh.primitive_supertoroid_add"
123 bl_label = "Add SuperToroid"
124 bl_description = "Construct a supertoroid mesh"
125 bl_options = {'REGISTER', 'UNDO', 'PRESET'}
127 SuperToroid : BoolProperty(name = "SuperToroid",
128 default = True,
129 description = "SuperToroid")
130 change : BoolProperty(name = "Change",
131 default = False,
132 description = "change SuperToroid")
134 R: FloatProperty(
135 name="Big radius",
136 description="The radius inside the tube",
137 default=1.0,
138 min=0.01, max=100.0
140 r: FloatProperty(
141 name="Small radius",
142 description="The radius of the tube",
143 default=0.3,
144 min=0.01, max=100.0
146 u: IntProperty(
147 name="U-segments",
148 description="Radial segmentation",
149 default=16,
150 min=3, max=265
152 v: IntProperty(
153 name="V-segments",
154 description="Lateral segmentation",
155 default=8,
156 min=3, max=265
158 n1: FloatProperty(
159 name="Ring manipulator",
160 description="Manipulates the shape of the Ring",
161 default=1.0,
162 min=0.01, max=100.0
164 n2: FloatProperty(
165 name="Cross manipulator",
166 description="Manipulates the shape of the cross-section",
167 default=1.0,
168 min=0.01, max=100.0
170 ie: BoolProperty(
171 name="Use Int. and Ext. radii",
172 description="Use internal and external radii",
173 default=False
175 edit: BoolProperty(
176 name="",
177 description="",
178 default=False,
179 options={'HIDDEN'}
182 def draw(self, context):
183 layout = self.layout
185 layout.prop(self, 'R', expand=True)
186 layout.prop(self, 'r', expand=True)
187 layout.prop(self, 'u', expand=True)
188 layout.prop(self, 'v', expand=True)
189 layout.prop(self, 'n1', expand=True)
190 layout.prop(self, 'n2', expand=True)
191 layout.prop(self, 'ie', expand=True)
193 if self.change == False:
194 col = layout.column(align=True)
195 col.prop(self, 'align', expand=True)
196 col = layout.column(align=True)
197 col.prop(self, 'location', expand=True)
198 col = layout.column(align=True)
199 col.prop(self, 'rotation', expand=True)
201 def execute(self, context):
202 # turn off 'Enter Edit Mode'
203 use_enter_edit_mode = bpy.context.preferences.edit.use_enter_edit_mode
204 bpy.context.preferences.edit.use_enter_edit_mode = False
206 props = self.properties
208 # check how the radii properties must be used
209 if props.ie:
210 rad1 = (props.R + props.r) / 2
211 rad2 = (props.R - props.r) / 2
212 # for consistency in the mesh, ie no crossing faces, make the largest of the two
213 # the outer radius
214 if rad2 > rad1:
215 [rad1, rad2] = [rad2, rad1]
216 else:
217 rad1 = props.R
218 rad2 = props.r
219 # again for consistency, make the radius in the tube,
220 # at least as big as the radius of the tube
221 if rad2 > rad1:
222 rad1 = rad2
224 if bpy.context.mode == "OBJECT":
225 if context.selected_objects != [] and context.active_object and \
226 (context.active_object.data is not None) and ('SuperToroid' in context.active_object.data.keys()) and \
227 (self.change == True):
228 obj = context.active_object
229 oldmesh = obj.data
230 oldmeshname = obj.data.name
231 verts, faces = supertoroid(rad1,
232 rad2,
233 props.u,
234 props.v,
235 props.n1,
236 props.n2
238 mesh = bpy.data.meshes.new('SuperToroid')
239 mesh.from_pydata(verts, [], faces)
240 obj.data = mesh
241 for material in oldmesh.materials:
242 obj.data.materials.append(material)
243 bpy.data.meshes.remove(oldmesh)
244 obj.data.name = oldmeshname
245 else:
246 verts, faces = supertoroid(rad1,
247 rad2,
248 props.u,
249 props.v,
250 props.n1,
251 props.n2
253 mesh = bpy.data.meshes.new('SuperToroid')
254 mesh.from_pydata(verts, [], faces)
255 obj = object_utils.object_data_add(context, mesh, operator=self)
257 obj.data["SuperToroid"] = True
258 obj.data["change"] = False
259 for prm in SuperToroidParameters():
260 obj.data[prm] = getattr(self, prm)
262 if bpy.context.mode == "EDIT_MESH":
263 active_object = context.active_object
264 name_active_object = active_object.name
265 bpy.ops.object.mode_set(mode='OBJECT')
266 verts, faces = supertoroid(rad1,
267 rad2,
268 props.u,
269 props.v,
270 props.n1,
271 props.n2
273 mesh = bpy.data.meshes.new('SuperToroid')
274 mesh.from_pydata(verts, [], faces)
275 obj = object_utils.object_data_add(context, mesh, operator=self)
276 obj.select_set(True)
277 active_object.select_set(True)
278 bpy.context.view_layer.objects.active = active_object
279 bpy.ops.object.join()
280 context.active_object.name = name_active_object
281 bpy.ops.object.mode_set(mode='EDIT')
283 if use_enter_edit_mode:
284 bpy.ops.object.mode_set(mode = 'EDIT')
286 # restore pre operator state
287 bpy.context.preferences.edit.use_enter_edit_mode = use_enter_edit_mode
289 return {'FINISHED'}
291 def SuperToroidParameters():
292 SuperToroidParameters = [
293 "R",
294 "r",
295 "u",
296 "v",
297 "n1",
298 "n2",
299 "ie",
300 "edit",
302 return SuperToroidParameters