Cleanup: camera_turnaround (pep8)
[blender-addons.git] / add_mesh_extra_objects / add_mesh_pyramid.py
blobc70988b7dd98f5e8f582ef46da9d1752257dc2ed
1 # GPL # "author": "Phil Cote, cotejrp1, (http://www.blenderaddons.com)"
3 import bpy
4 import bmesh
5 from bpy.props import (
6 FloatProperty,
7 IntProperty,
8 StringProperty,
9 BoolProperty,
11 from math import pi
12 from mathutils import (
13 Quaternion,
14 Vector,
16 from bpy_extras import object_utils
19 def create_step(width, base_level, step_height, num_sides):
21 axis = [0, 0, -1]
22 PI2 = pi * 2
23 rad = width / 2
25 quat_angles = [(cur_side / num_sides) * PI2
26 for cur_side in range(num_sides)]
28 quaternions = [Quaternion(axis, quat_angle)
29 for quat_angle in quat_angles]
31 init_vectors = [Vector([rad, 0, base_level])] * len(quaternions)
33 quat_vector_pairs = list(zip(quaternions, init_vectors))
34 vectors = [quaternion @ vec for quaternion, vec in quat_vector_pairs]
35 bottom_list = [(vec.x, vec.y, vec.z) for vec in vectors]
36 top_list = [(vec.x, vec.y, vec.z + step_height) for vec in vectors]
37 full_list = bottom_list + top_list
39 return full_list
42 def split_list(l, n):
43 """
44 split the blocks up. Credit to oremj for this one.
45 http://stackoverflow.com/questions/312443/how-do-you-split-a-list-into-evenly-sized-chunks-in-python
46 """
47 n *= 2
48 returned_list = [l[i: i + n] for i in range(0, len(l), n)]
49 return returned_list
52 def get_connector_pairs(lst, n_sides):
53 # chop off the verts that get used for the base and top
54 lst = lst[n_sides:]
55 lst = lst[:-n_sides]
56 lst = split_list(lst, n_sides)
57 return lst
60 def pyramid_mesh(self, context):
61 all_verts = []
63 height_offset = 0
64 cur_width = self.width
66 for i in range(self.num_steps):
67 verts_loc = create_step(cur_width, height_offset, self.height,
68 self.num_sides)
69 height_offset += self.height
70 cur_width -= self.reduce_by
71 all_verts.extend(verts_loc)
73 mesh = bpy.data.meshes.new("Pyramid")
74 bm = bmesh.new()
76 for v_co in all_verts:
77 bm.verts.new(v_co)
79 def add_faces(n, block_vert_sets):
80 for bvs in block_vert_sets:
81 for i in range(self.num_sides - 1):
82 bm.faces.new([bvs[i], bvs[i + n], bvs[i + n + 1], bvs[i + 1]])
83 bm.faces.new([bvs[n - 1], bvs[(n * 2) - 1], bvs[n], bvs[0]])
85 # get the base and cap faces done.
86 bm.faces.new(bm.verts[0:self.num_sides])
87 bm.faces.new(reversed(bm.verts[-self.num_sides:])) # otherwise normal faces intern... T44619.
89 # side faces
90 block_vert_sets = split_list(bm.verts, self.num_sides)
91 add_faces(self.num_sides, block_vert_sets)
93 # connector faces between faces and faces of the block above it.
94 connector_pairs = get_connector_pairs(bm.verts, self.num_sides)
95 add_faces(self.num_sides, connector_pairs)
97 bm.to_mesh(mesh)
98 mesh.update()
100 return mesh
103 class AddPyramid(bpy.types.Operator, object_utils.AddObjectHelper):
104 bl_idname = "mesh.primitive_steppyramid_add"
105 bl_label = "Pyramid"
106 bl_description = "Construct a step pyramid mesh"
107 bl_options = {'REGISTER', 'UNDO', 'PRESET'}
109 Pyramid : BoolProperty(name = "Pyramid",
110 default = True,
111 description = "Pyramid")
112 change : BoolProperty(name = "Change",
113 default = False,
114 description = "change Pyramid")
116 num_sides: IntProperty(
117 name="Number Sides",
118 description="How many sides each step will have",
119 min=3,
120 default=4
122 num_steps: IntProperty(
123 name="Number of Steps",
124 description="How many steps for the overall pyramid",
125 min=1,
126 default=10
128 width: FloatProperty(
129 name="Initial Width",
130 description="Initial base step width",
131 min=0.01,
132 default=2
134 height: FloatProperty(
135 name="Height",
136 description="How tall each step will be",
137 min=0.01,
138 default=0.1
140 reduce_by: FloatProperty(
141 name="Reduce Step By",
142 description="How much to reduce each succeeding step by",
143 min=.01,
144 default=.20
147 def draw(self, context):
148 layout = self.layout
150 layout.prop(self, 'num_sides', expand=True)
151 layout.prop(self, 'num_steps', expand=True)
152 layout.prop(self, 'width', expand=True)
153 layout.prop(self, 'height', expand=True)
154 layout.prop(self, 'reduce_by', expand=True)
156 if self.change == False:
157 col = layout.column(align=True)
158 col.prop(self, 'align', expand=True)
159 col = layout.column(align=True)
160 col.prop(self, 'location', expand=True)
161 col = layout.column(align=True)
162 col.prop(self, 'rotation', expand=True)
164 def execute(self, context):
165 # turn off 'Enter Edit Mode'
166 use_enter_edit_mode = bpy.context.preferences.edit.use_enter_edit_mode
167 bpy.context.preferences.edit.use_enter_edit_mode = False
169 if bpy.context.mode == "OBJECT":
170 if context.selected_objects != [] and context.active_object and \
171 ('Pyramid' in context.active_object.data.keys()) and (self.change == True):
172 obj = context.active_object
173 oldmesh = obj.data
174 oldmeshname = obj.data.name
175 obj.data = pyramid_mesh(self, context)
176 for material in oldmesh.materials:
177 obj.data.materials.append(material)
178 bpy.data.meshes.remove(oldmesh)
179 obj.data.name = oldmeshname
180 else:
181 mesh = pyramid_mesh(self, context)
182 obj = object_utils.object_data_add(context, mesh, operator=self)
184 obj.data["Pyramid"] = True
185 obj.data["change"] = False
186 for prm in PyramidParameters():
187 obj.data[prm] = getattr(self, prm)
189 if bpy.context.mode == "EDIT_MESH":
190 active_object = context.active_object
191 name_active_object = active_object.name
192 bpy.ops.object.mode_set(mode='OBJECT')
193 mesh = pyramid_mesh(self, context)
194 obj = object_utils.object_data_add(context, mesh, operator=self)
195 obj.select_set(True)
196 active_object.select_set(True)
197 bpy.ops.object.join()
198 context.active_object.name = name_active_object
199 bpy.ops.object.mode_set(mode='EDIT')
201 if use_enter_edit_mode:
202 bpy.ops.object.mode_set(mode = 'EDIT')
204 # restore pre operator state
205 bpy.context.preferences.edit.use_enter_edit_mode = use_enter_edit_mode
207 return {'FINISHED'}
209 def PyramidParameters():
210 PyramidParameters = [
211 "num_sides",
212 "num_steps",
213 "width",
214 "height",
215 "reduce_by",
217 return PyramidParameters