diff --git a/add_mesh_extra_objects/add_mesh_pyramid.py b/add_mesh_extra_objects/add_mesh_pyramid.py index da14e998638386a04a419f318119db265e6f0df9..e99ffd9aeb13f82d90124e349adbb837c43bfd2d 100644 --- a/add_mesh_extra_objects/add_mesh_pyramid.py +++ b/add_mesh_extra_objects/add_mesh_pyramid.py @@ -22,7 +22,7 @@ bl_info = { 'name': 'Mesh Pyramid', 'author': 'Phil Cote, cotejrp1, (http://www.blenderaddons.com)', - 'version': (0, 4), + 'version': (0, 5), "blender": (2, 6, 3), 'location': 'View3D > Add > Mesh', 'description': 'Create an egyption-style step pyramid', @@ -32,111 +32,133 @@ bl_info = { import bpy import bmesh - -from bpy.props import IntProperty, FloatProperty +from bpy.props import FloatProperty, IntProperty +from math import pi +from mathutils import Quaternion, Vector from bpy_extras.object_utils import AddObjectHelper, object_data_add -def makePyramid(initial_size, step_height, step_width, number_steps): - - vert_list = [] - face_list = [] - - cur_size = initial_size # how large each step will be overall - - # b = buttom, t = top, f = front, b = back, l = left, r = right - x = y = z = 0 - voffset = 0 # relative vert indices to help make faces fo each step - sn = 0 # step number - - while sn < number_steps: - # bottom verts for this iteration - bfl = (x, y, z) - bfr = (x + cur_size, y, z) - bbl = (x, y + cur_size, z) - bbr = (x + cur_size, y + cur_size, z) - - # top verts for this iteration. - tfl = (x, y, z + step_height) - tfr = (x + cur_size, y, z + step_height) - tbl = (x, y + cur_size, z + step_height) - tbr = (x + cur_size, y + cur_size, z + step_height) - - # add to the vert buffer - vert_list.extend((bfl, bfr, bbl, bbr, tfl, tfr, tbl, tbr,)) +def create_step(width, base_level, step_height, num_sides): + + axis = [0,0,-1] + PI2 = pi * 2 + rad = width / 2 + + quat_angles = [(cur_side/num_sides) * PI2 + for cur_side in range(num_sides)] + + quaternions = [Quaternion(axis, quat_angle) + for quat_angle in quat_angles] + + init_vectors = [Vector([rad, 0, base_level]) + for quat in quaternions] + + quat_vector_pairs = list(zip(quaternions, init_vectors)) + vectors = [quaternion * vec for quaternion, vec in quat_vector_pairs] + bottom_list = [(vec.x, vec.y, vec.z) for vec in vectors] + top_list = [(vec.x, vec.y, vec.z+step_height) for vec in vectors] + full_list = bottom_list + top_list + return full_list + + +def split_list(l, n): + """ + split the blocks up. Credit to oremj for this one. + http://stackoverflow.com/questions/312443/how-do-you-split-a-list-into-evenly-sized-chunks-in-python + """ + n *= 2 + returned_list = [l[i:i+n] for i in range(0, len(l), n)] + return returned_list + - # side faces - face_list.extend(( - (voffset + 4, voffset + 5, voffset + 1, voffset + 0), # back - (voffset + 6, voffset + 7, voffset + 3, voffset + 2), # front - (voffset + 2, voffset + 6, voffset + 4, voffset + 0), # left - (voffset + 3, voffset + 7, voffset + 5, voffset + 1), # right - )) - - # horizontal connecting faces ( note: n/a for the first iteration ). - if voffset > 0: - face_list.extend(( - (voffset - 4, voffset - 3, voffset + 1, voffset + 0), # connector front - (voffset - 2, voffset - 1, voffset + 3, voffset + 2), # back - (voffset - 4, voffset - 2, voffset + 2, voffset + 0), # left - (voffset - 3, voffset - 1, voffset + 3, voffset + 1), # right - )) - - # set up parameters for the next iteration - cur_size = cur_size - (step_width * 2) - x = x + step_width - y = y + step_width - z = z + step_height - sn = sn + 1 - voffset = voffset + 8 - - voffset = voffset - 8 # remove extra voffset done on final iteration - face_list.extend(( - (voffset + 6, voffset + 7, voffset + 5, voffset + 4), # cap the top. - (2, 3, 1, 0), # cap the bottom. - )) - - return vert_list, face_list +def get_connector_pairs(lst, n_sides): + # chop off the verts that get used for the base and top + lst = lst[n_sides:] + lst = lst[:-n_sides] + lst = split_list(lst, n_sides) + return lst def add_pyramid_object(self, context): - verts, faces = makePyramid(self.initial_size, self.step_height, - self.step_width, self.number_steps) - bm = bmesh.new() - mesh = bpy.data.meshes.new(name="Pyramid") - - for vert in verts: - bm.verts.new(vert) - - for face in faces: - bm.faces.new([bm.verts[i] for i in face]) + all_verts = [] + + height_offset = 0 + cur_width = self.width + + for i in range(self.num_steps): + verts_loc = create_step(cur_width, height_offset, self.height, + self.num_sides) + height_offset += self.height + cur_width -= self.reduce_by + all_verts.extend(verts_loc) + + mesh = bpy.data.meshes.new("Pyramid") + bm = bmesh.new() + + for v_co in all_verts: + bm.verts.new(v_co) + + + # do the sides. + n = self.num_sides + + def add_faces(n, block_vert_sets): + for bvs in block_vert_sets: + for i in range(self.num_sides-1): + bm.faces.new([bvs[i], bvs[i+n], bvs[i+n+1], bvs[i+1]]) + bm.faces.new([bvs[n-1], bvs[(n*2)-1], bvs[n], bvs[0]]) + + + # get the base and cap faces done. + bm.faces.new(bm.verts[0:self.num_sides]) + bm.faces.new(bm.verts[-self.num_sides:]) + + # side faces + block_vert_sets = split_list(bm.verts, self.num_sides) + add_faces(self.num_sides, block_vert_sets) + + # connector faces between faces and faces of the block above it. + connector_pairs = get_connector_pairs(bm.verts, self.num_sides) + add_faces(self.num_sides, connector_pairs) + + bm.to_mesh(mesh) + mesh.update() + res = object_data_add(context, mesh, operator=self) - bm.to_mesh(mesh) - mesh.update() - res = object_data_add(context, mesh, operator=self) - class AddPyramid(bpy.types.Operator, AddObjectHelper): - """Add a Mesh Object""" + '''Add a mesh pyramid''' bl_idname = "mesh.primitive_steppyramid_add" bl_label = "Pyramid" bl_options = {'REGISTER', 'UNDO', 'PRESET'} - initial_size = FloatProperty(name="Initial Size", default=2.0, - min=0.0, max=20.0, - description="Set the initial size at the pyramid base") - - step_height = FloatProperty(name="Step Height", default=0.1, - min=0.0, max=10.0, - description="How tall each of the steps will be") - - step_width = FloatProperty(name="Step Width", default=0.1, - min=0.0, max=10.0, - description="How wide each step will be") - - number_steps = IntProperty(name="Number Steps", default=10, - min=1, max=20, - description="Total number of steps") + + num_sides = IntProperty( + name="Number Sides", + description = "How many sides each step will have", + min = 3, max = 20, default=4) + num_steps = IntProperty( + name="Number of Steps", + description="How many steps for the overall pyramid", + min=1, max=20, default=10) + + width = FloatProperty( + name="Initial Width", + description="Initial base step width", + min=0.01, max=100.0, + default=2) + + height = FloatProperty( + name="Height", + description="How tall each step will be", + min=0.01, max=100.0, + default=0.1) + + reduce_by = FloatProperty( + name="Reduce Step By", + description = "How much to reduce each succeeding step by", + min=.01, max = 2.0, default= .20) + def execute(self, context): add_pyramid_object(self, context) @@ -144,17 +166,16 @@ class AddPyramid(bpy.types.Operator, AddObjectHelper): ''' def menu_func(self, context): - self.layout.operator(OBJECT_OT_add_pyramid.bl_idname, - text="Pyramid", icon="PLUGIN") + self.layout.operator(AddPyramid.bl_idname, icon='PLUGIN') def register(): - bpy.utils.register_class(OBJECT_OT_add_pyramid) + bpy.utils.register_class(AddPyramid) bpy.types.INFO_MT_mesh_add.append(menu_func) def unregister(): - bpy.utils.unregister_class(OBJECT_OT_add_pyramid) + bpy.utils.unregister_class(AddPyramid) bpy.types.INFO_MT_mesh_add.remove(menu_func) if __name__ == "__main__":