3 "name": "Add Mesh: SuperToroid",
4 "author": "DreamPainter",
7 "location": "View3D > Add > Mesh > SuperToroid",
8 "description": "Add a SuperToroid mesh",
9 "url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/" \
10 "Scripts/Add_Mesh/", # no url
11 "category": "Add Mesh"}
14 from bpy
.props
import FloatProperty
,BoolProperty
,IntProperty
15 from math
import pi
, cos
, sin
16 from mathutils
import Vector
17 from bpy_extras
import object_utils
19 # Create a new mesh (object) from verts/edges/faces.
20 # verts/edges/faces ... List of vertices/edges/faces for the
21 # new mesh (as used in from_pydata).
22 # name ... Name of the new mesh (& object).
23 def create_mesh_object(context
, verts
, edges
, faces
, name
):
26 mesh
= bpy
.data
.meshes
.new(name
)
28 # Make a mesh from a list of verts/edges/faces.
29 mesh
.from_pydata(verts
, edges
, faces
)
31 # Update mesh geometry after adding stuff.
34 from bpy_extras
import object_utils
35 return object_utils
.object_data_add(context
, mesh
, operator
=None)
37 # A very simple "bridge" tool.
38 # Connects two equally long vertex rows with faces.
39 # Returns a list of the new faces (list of lists)
41 # vertIdx1 ... First vertex list (list of vertex indices).
42 # vertIdx2 ... Second vertex list (list of vertex indices).
43 # closed ... Creates a loop (first & last are closed).
44 # flipped ... Invert the normal of the face(s).
46 # Note: You can set vertIdx1 to a single vertex index to create
47 # a fan/star of faces.
48 # Note: If both vertex idx list are the same length they have
49 # to have at least 2 vertices.
50 def createFaces(vertIdx1
, vertIdx2
, closed
=False, flipped
=False):
53 if not vertIdx1
or not vertIdx2
:
56 if len(vertIdx1
) < 2 and len(vertIdx2
) < 2:
60 if (len(vertIdx1
) != len(vertIdx2
)):
61 if (len(vertIdx1
) == 1 and len(vertIdx2
) > 1):
69 # Bridge the start with the end.
76 face
.append(vertIdx1
[total
- 1])
80 face
= [vertIdx2
[0], vertIdx1
[0]]
82 face
.append(vertIdx1
[total
- 1])
83 face
.append(vertIdx2
[total
- 1])
86 # Bridge the rest of the faces.
87 for num
in range(total
- 1):
90 face
= [vertIdx2
[num
], vertIdx1
[0], vertIdx2
[num
+ 1]]
92 face
= [vertIdx2
[num
], vertIdx1
[num
],
93 vertIdx1
[num
+ 1], vertIdx2
[num
+ 1]]
97 face
= [vertIdx1
[0], vertIdx2
[num
], vertIdx2
[num
+ 1]]
99 face
= [vertIdx1
[num
], vertIdx2
[num
],
100 vertIdx2
[num
+ 1], vertIdx1
[num
+ 1]]
110 def supertoroid(R
,r
,u
,v
,n1
,n2
):
114 u = lateral segmentation
115 v = radial segmentation
116 n1 = value determines the shape of the torus
117 n2 = value determines the shape of the cross-section
120 # create the necessary constants
127 # create each cross-section by calculating each vector on the
129 # x = (cos(theta)**n1)*(R+r*(cos(phi)**n2))
130 # y = (sin(theta)**n1)*(R+r*(cos(phi)**n2))
131 # z = (r*sin(phi)**n2)
132 # with theta and phi rangeing from 0 to 2pi
134 s
= power(sin(i
*a
),n1
)
135 c
= power(cos(i
*a
),n1
)
137 c2
= R
+r
*power(cos(j
*b
),n2
)
138 s2
= r
*power(sin(j
*b
),n2
)
139 verts
.append(Vector((c
*c2
,s
*c2
,s2
)))
140 # bridge the last circle with the previous circle
141 if i
> 0: # but not for the first circle, 'cus there's no previous before the first
142 f
= createFaces(range((i
-1)*v
,i
*v
),range(i
*v
,(i
+1)*v
),closed
= True)
144 # bridge the last circle with the first
145 f
= createFaces(range((u
-1)*v
,u
*v
),range(v
),closed
=True)
150 class add_supertoroid(bpy
.types
.Operator
):
151 """Add a SuperToroid"""
152 bl_idname
= "mesh.primitive_supertoroid_add"
153 bl_label
= "Add SuperToroid"
154 bl_description
= "Create a SuperToroid"
155 bl_options
= {'REGISTER', 'UNDO', 'PRESET'}
157 R
= FloatProperty(name
= "big radius",
158 description
= "The radius inside the tube",
159 default
= 1.0, min = 0.01, max = 100.0)
160 r
= FloatProperty(name
= "small radius",
161 description
= "The radius of the tube",
162 default
= 0.3, min = 0.01, max = 100.0)
163 u
= IntProperty(name
= "U-segments",
164 description
= "radial segmentation",
165 default
= 16, min = 3, max = 265)
166 v
= IntProperty(name
= "V-segments",
167 description
= "lateral segmentation",
168 default
= 8, min = 3, max = 265)
169 n1
= FloatProperty(name
= "Ring manipulator",
170 description
= "Manipulates the shape of the Ring",
171 default
= 1.0, min = 0.01, max = 100.0)
172 n2
= FloatProperty(name
= "Cross manipulator",
173 description
= "Manipulates the shape of the cross-section",
174 default
= 1.0, min = 0.01, max = 100.0)
175 ie
= BoolProperty(name
= "Use Int.+Ext. radii",
176 description
= "Use internal and external radii",
178 edit
= BoolProperty(name
="",
183 def execute(self
,context
):
184 props
= self
.properties
186 # check how the radii properties must be used
188 rad1
= (props
.R
+props
.r
)/2
189 rad2
= (props
.R
-props
.r
)/2
190 # for consistency in the mesh, ie no crossing faces, make the largest of the two
193 [rad1
,rad2
] = [rad2
,rad1
]
197 # again for consistency, make the radius in the tube,
198 # at least as big as the radius of the tube
203 verts
,faces
= supertoroid(rad1
,
211 obj
= create_mesh_object(context
, verts
, [], faces
, "SuperToroid")
216 menu_func = lambda self, context: self.layout.operator(add_supertoroid.bl_idname,
217 text = "SuperToroid", icon = 'PLUGIN')
220 bpy.types.register(add_supertoroid)
221 bpy.types.INFO_MT_mesh_add.append(menu_func)
224 bpy.types.unregister(add_supertoroid)
225 bpy.types.INFO_MT_mesh_add.remove(menu_func)
227 if __name__ == "__main__":