1 # SPDX-FileCopyrightText: 2015-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 # Original by Fourmadmen
8 from mathutils
import (
13 from bpy
.props
import (
19 from bpy_extras
import object_utils
21 # Create a new mesh (object) from verts/edges/faces.
22 # verts/edges/faces ... List of vertices/edges/faces for the
23 # new mesh (as used in from_pydata)
24 # name ... Name of the new mesh (& object)
26 def create_mesh_object(context
, verts
, edges
, faces
, name
):
29 mesh
= bpy
.data
.meshes
.new(name
)
31 # Make a mesh from a list of verts/edges/faces.
32 mesh
.from_pydata(verts
, edges
, faces
)
34 # Update mesh geometry after adding stuff.
37 from bpy_extras
import object_utils
38 return object_utils
.object_data_add(context
, mesh
, operator
=None)
41 # A very simple "bridge" tool.
43 def createFaces(vertIdx1
, vertIdx2
, closed
=False, flipped
=False):
46 if not vertIdx1
or not vertIdx2
:
49 if len(vertIdx1
) < 2 and len(vertIdx2
) < 2:
53 if (len(vertIdx1
) != len(vertIdx2
)):
54 if (len(vertIdx1
) == 1 and len(vertIdx2
) > 1):
62 # Bridge the start with the end.
69 face
.append(vertIdx1
[total
- 1])
73 face
= [vertIdx2
[0], vertIdx1
[0]]
75 face
.append(vertIdx1
[total
- 1])
76 face
.append(vertIdx2
[total
- 1])
79 # Bridge the rest of the faces.
80 for num
in range(total
- 1):
83 face
= [vertIdx2
[num
], vertIdx1
[0], vertIdx2
[num
+ 1]]
85 face
= [vertIdx2
[num
], vertIdx1
[num
],
86 vertIdx1
[num
+ 1], vertIdx2
[num
+ 1]]
90 face
= [vertIdx1
[0], vertIdx2
[num
], vertIdx2
[num
+ 1]]
92 face
= [vertIdx1
[num
], vertIdx2
[num
],
93 vertIdx2
[num
+ 1], vertIdx1
[num
+ 1]]
99 # @todo Clean up vertex&face creation process a bit.
101 def add_star(points
, outer_radius
, inner_radius
, height
):
108 segments
= points
* 2
110 half_height
= height
/ 2.0
112 vert_idx_top
= len(verts
)
113 verts
.append(Vector((0.0, 0.0, half_height
)))
115 vert_idx_bottom
= len(verts
)
116 verts
.append(Vector((0.0, 0.0, -half_height
)))
121 for index
in range(segments
):
122 quat
= Quaternion(z_axis
, (index
/ segments
) * PI_2
)
126 radius
= outer_radius
129 radius
= inner_radius
131 edgeloop_top
.append(len(verts
))
132 vec
= quat
@ Vector((radius
, 0, half_height
))
135 edgeloop_bottom
.append(len(verts
))
136 vec
= quat
@ Vector((radius
, 0, -half_height
))
139 faces_top
= createFaces([vert_idx_top
], edgeloop_top
, closed
=True)
140 faces_outside
= createFaces(edgeloop_top
, edgeloop_bottom
, closed
=True)
141 faces_bottom
= createFaces([vert_idx_bottom
], edgeloop_bottom
,
142 flipped
=True, closed
=True)
144 faces
.extend(faces_top
)
145 faces
.extend(faces_outside
)
146 faces
.extend(faces_bottom
)
151 class AddStar(bpy
.types
.Operator
, object_utils
.AddObjectHelper
):
152 bl_idname
= "mesh.primitive_star_add"
153 bl_label
= "Simple Star"
154 bl_description
= "Construct a star mesh"
155 bl_options
= {'REGISTER', 'UNDO', 'PRESET'}
157 Star
: BoolProperty(name
= "Star",
159 description
= "Star")
160 change
: BoolProperty(name
= "Change",
162 description
= "change Star")
166 description
="Number of points for the star",
171 outer_radius
: FloatProperty(
173 description
="Outer radius of the star",
178 innter_radius
: FloatProperty(
180 description
="Inner radius of the star",
185 height
: FloatProperty(name
="Height",
186 description
="Height of the star",
192 def draw(self
, context
):
195 layout
.prop(self
, 'points', expand
=True)
196 layout
.prop(self
, 'outer_radius', expand
=True)
197 layout
.prop(self
, 'innter_radius', expand
=True)
198 layout
.prop(self
, 'height', expand
=True)
200 if self
.change
== False:
201 col
= layout
.column(align
=True)
202 col
.prop(self
, 'align', expand
=True)
203 col
= layout
.column(align
=True)
204 col
.prop(self
, 'location', expand
=True)
205 col
= layout
.column(align
=True)
206 col
.prop(self
, 'rotation', expand
=True)
208 def execute(self
, context
):
209 # turn off 'Enter Edit Mode'
210 use_enter_edit_mode
= bpy
.context
.preferences
.edit
.use_enter_edit_mode
211 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= False
213 if bpy
.context
.mode
== "OBJECT":
214 if context
.selected_objects
!= [] and context
.active_object
and \
215 (context
.active_object
.data
is not None) and ('Star' in context
.active_object
.data
.keys()) and \
216 (self
.change
== True):
217 obj
= context
.active_object
219 oldmeshname
= obj
.data
.name
220 verts
, faces
= add_star(
226 mesh
= bpy
.data
.meshes
.new('Star')
227 mesh
.from_pydata(verts
, [], faces
)
229 for material
in oldmesh
.materials
:
230 obj
.data
.materials
.append(material
)
231 bpy
.data
.meshes
.remove(oldmesh
)
232 obj
.data
.name
= oldmeshname
234 verts
, faces
= add_star(
240 mesh
= bpy
.data
.meshes
.new('Star')
241 mesh
.from_pydata(verts
, [], faces
)
242 obj
= object_utils
.object_data_add(context
, mesh
, operator
=self
)
244 obj
.data
["Star"] = True
245 obj
.data
["change"] = False
246 for prm
in StarParameters():
247 obj
.data
[prm
] = getattr(self
, prm
)
249 if bpy
.context
.mode
== "EDIT_MESH":
250 active_object
= context
.active_object
251 name_active_object
= active_object
.name
252 bpy
.ops
.object.mode_set(mode
='OBJECT')
253 verts
, faces
= add_star(
259 mesh
= bpy
.data
.meshes
.new('Star')
260 mesh
.from_pydata(verts
, [], faces
)
261 obj
= object_utils
.object_data_add(context
, mesh
, operator
=self
)
263 active_object
.select_set(True)
264 bpy
.context
.view_layer
.objects
.active
= active_object
265 bpy
.ops
.object.join()
266 context
.active_object
.name
= name_active_object
267 bpy
.ops
.object.mode_set(mode
='EDIT')
269 if use_enter_edit_mode
:
270 bpy
.ops
.object.mode_set(mode
= 'EDIT')
272 # restore pre operator state
273 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= use_enter_edit_mode
277 def StarParameters():
284 return StarParameters