From 40c00d312f0cc54485f93e47763eb9cd9b413fee Mon Sep 17 00:00:00 2001 From: Brendon Murphy Date: Fri, 1 May 2015 10:52:03 +0800 Subject: add_extra_mesh_objects: new version Tracker: https://developer.blender.org/T44561 New UI, New Addons, Better organization & removal of 'Lesser Object Types' Merged & removed "lesser" & 'larger" add mesh scripts. Menu updates & re-organization & modernize. New: Add Vert, Round Cube, Menger Cube, Brilliant Diamond, Parent to Empty Removed: Add Mesh: Sqorus, Trapezohedron, Wedge, Polysphere. Merged add_mesh_symmetrical_empty from contrib Documentation: http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/Add_Mesh/Add_Mesh_Extra_Objects --- add_mesh_extra_objects/__init__.py | 121 +++-- add_mesh_extra_objects/add_empty_as_parent.py | 57 +++ .../add_mesh_3d_function_surface.py | 36 +- add_mesh_extra_objects/add_mesh_extra_objects.py | 486 --------------------- add_mesh_extra_objects/add_mesh_gears.py | 27 +- add_mesh_extra_objects/add_mesh_gemstones.py | 37 +- add_mesh_extra_objects/add_mesh_honeycomb.py | 41 +- add_mesh_extra_objects/add_mesh_menger_sponge.py | 185 ++++++++ add_mesh_extra_objects/add_mesh_pipe_joint.py | 39 +- add_mesh_extra_objects/add_mesh_polysphere.py | 79 ---- add_mesh_extra_objects/add_mesh_pyramid.py | 51 +-- add_mesh_extra_objects/add_mesh_round_brilliant.py | 365 ++++++++++++++++ add_mesh_extra_objects/add_mesh_round_cube.py | 479 ++++++++++++++++++++ add_mesh_extra_objects/add_mesh_solid.py | 25 +- add_mesh_extra_objects/add_mesh_star.py | 174 ++++++++ add_mesh_extra_objects/add_mesh_supertoroid.py | 20 +- add_mesh_extra_objects/add_mesh_teapot.py | 28 +- add_mesh_extra_objects/add_mesh_torusknot.py | 27 +- add_mesh_extra_objects/add_mesh_twisted_torus.py | 45 +- add_mesh_extra_objects/add_mesh_vertex.py | 142 ++++++ 20 files changed, 1503 insertions(+), 961 deletions(-) create mode 100644 add_mesh_extra_objects/add_empty_as_parent.py delete mode 100644 add_mesh_extra_objects/add_mesh_extra_objects.py create mode 100644 add_mesh_extra_objects/add_mesh_menger_sponge.py delete mode 100644 add_mesh_extra_objects/add_mesh_polysphere.py create mode 100644 add_mesh_extra_objects/add_mesh_round_brilliant.py create mode 100644 add_mesh_extra_objects/add_mesh_round_cube.py create mode 100644 add_mesh_extra_objects/add_mesh_star.py create mode 100644 add_mesh_extra_objects/add_mesh_vertex.py diff --git a/add_mesh_extra_objects/__init__.py b/add_mesh_extra_objects/__init__.py index 41bebc7f..9cd18128 100644 --- a/add_mesh_extra_objects/__init__.py +++ b/add_mesh_extra_objects/__init__.py @@ -16,13 +16,13 @@ # # ##### END GPL LICENSE BLOCK ##### # Contributed to by -# Pontiac, Fourmadmen, varkenvarken, tuga3d, meta-androcto, metalliandy, dreampainter & cotejrp1# +# Pontiac, Fourmadmen, varkenvarken, tuga3d, meta-androcto, metalliandy, dreampainter, cotejrp1# bl_info = { "name": "Extra Objects", "author": "Multiple Authors", "version": (0, 3, 0), - "blender": (2, 72, 0), + "blender": (2, 74, 0), "location": "View3D > Add > Mesh", "description": "Add extra mesh object types", "warning": "", @@ -33,12 +33,12 @@ bl_info = { if "bpy" in locals(): import importlib - importlib.reload(add_mesh_extra_objects) + importlib.reload(add_mesh_star) importlib.reload(add_mesh_twisted_torus) importlib.reload(add_mesh_gemstones) importlib.reload(add_mesh_gears) importlib.reload(add_mesh_3d_function_surface) - importlib.reload(add_mesh_polysphere) + importlib.reload(add_mesh_round_cube) importlib.reload(add_mesh_supertoroid) importlib.reload(add_mesh_pyramid) importlib.reload(add_mesh_torusknot) @@ -46,14 +46,17 @@ if "bpy" in locals(): importlib.reload(add_mesh_teapot) importlib.reload(add_mesh_pipe_joint) importlib.reload(add_mesh_solid) - + importlib.reload(add_mesh_round_brilliant) + importlib.reload(add_mesh_menger_sponge) + importlib.reload(add_mesh_vertex) + importlib.reload(add_empty_as_parent) else: - from . import add_mesh_extra_objects + from . import add_mesh_star from . import add_mesh_twisted_torus from . import add_mesh_gemstones from . import add_mesh_gears from . import add_mesh_3d_function_surface - from . import add_mesh_polysphere + from . import add_mesh_round_cube from . import add_mesh_supertoroid from . import add_mesh_pyramid from . import add_mesh_torusknot @@ -61,9 +64,33 @@ else: from . import add_mesh_teapot from . import add_mesh_pipe_joint from . import add_mesh_solid + from . import add_mesh_round_brilliant + from . import add_mesh_menger_sponge + from . import add_mesh_vertex + from . import add_empty_as_parent + import bpy + +class INFO_MT_mesh_vert_add(bpy.types.Menu): + # Define the "Pipe Joints" menu + bl_idname = "INFO_MT_mesh_vert_add" + bl_label = "Single Vert" + + def draw(self, context): + layout = self.layout + layout.operator_context = 'INVOKE_REGION_WIN' + layout.operator("mesh.primitive_vert_add", + text="Add Single Vert ") + layout.operator("mesh.primitive_emptyvert_add", + text="Object Origin Only") + layout.operator("mesh.primitive_symmetrical_vert_add", + text="Origin & Vert Mirrored") + layout.operator("mesh.primitive_symmetrical_empty_add", + text="Object Origin Mirrored") + + class INFO_MT_mesh_gears_add(bpy.types.Menu): # Define the "Gears" menu bl_idname = "INFO_MT_mesh_gears_add" @@ -77,6 +104,23 @@ class INFO_MT_mesh_gears_add(bpy.types.Menu): layout.operator("mesh.primitive_worm_gear", text="Worm") + +class INFO_MT_mesh_diamonds_add(bpy.types.Menu): + # Define the "Gears" menu + bl_idname = "INFO_MT_mesh_diamonds_add" + bl_label = "Diamonds" + + def draw(self, context): + layout = self.layout + layout.operator_context = 'INVOKE_REGION_WIN' + layout.operator("mesh.primitive_brilliant_add", + text="Brilliant Diamond") + layout.operator("mesh.primitive_diamond_add", + text="Diamond") + layout.operator("mesh.primitive_gem_add", + text="Gem") + + class INFO_MT_mesh_math_add(bpy.types.Menu): # Define the "Math Function" menu bl_idname = "INFO_MT_mesh_math_add" @@ -89,27 +133,29 @@ class INFO_MT_mesh_math_add(bpy.types.Menu): text="Z Math Surface") layout.operator("mesh.primitive_xyz_function_surface", text="XYZ Math Surface") - self.layout.operator("mesh.primitive_solid_add", text="Solid") + self.layout.operator("mesh.primitive_solid_add", text="Regular Solid") + -class INFO_MT_mesh_basic_add(bpy.types.Menu): +class INFO_MT_mesh_extras_add(bpy.types.Menu): # Define the "Simple Objects" menu - bl_idname = "INFO_MT_mesh_basic_add" - bl_label = "Simple Objects" + bl_idname = "INFO_MT_mesh_extras_add" + bl_label = "Extras" def draw(self, context): layout = self.layout layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator("mesh.primitive_diamond_add", - text="Diamond") - layout.operator("mesh.primitive_gem_add", - text="Gem") - layout.operator("mesh.primitive_sqorus_add", - text="Sqorus") - layout.operator("mesh.primitive_wedge_add") + layout.menu("INFO_MT_mesh_diamonds_add", text="Diamonds", icon="PMARKER_SEL") layout.operator("mesh.primitive_star_add", - text="Star") - layout.operator("mesh.primitive_trapezohedron_add", - text="Trapezohedron") + text="Simple Star") + layout.operator("mesh.primitive_steppyramid_add", + text="Step Pyramid") + layout.operator("mesh.honeycomb_add", + text="Honeycomb") + layout.operator("mesh.primitive_teapot_add", + text="Teapot+") + layout.operator("mesh.menger_sponge_add", + text="Menger Sponge") + class INFO_MT_mesh_torus_add(bpy.types.Menu): # Define the "Simple Objects" menu @@ -126,20 +172,6 @@ class INFO_MT_mesh_torus_add(bpy.types.Menu): layout.operator("mesh.primitive_torusknot_add", text="Torus Knot") -class INFO_MT_mesh_misc_add(bpy.types.Menu): - # Define the "Simple Objects" menu - bl_idname = "INFO_MT_mesh_misc_add" - bl_label = "Misc Objects" - - def draw(self, context): - layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator("mesh.primitive_steppyramid_add", - text="Step Pyramid") - layout.operator("mesh.honeycomb_add", - text="Honeycomb") - layout.operator("mesh.primitive_teapot_add", - text="Teapot+") class INFO_MT_mesh_pipe_joints_add(bpy.types.Menu): # Define the "Pipe Joints" menu @@ -160,17 +192,22 @@ class INFO_MT_mesh_pipe_joints_add(bpy.types.Menu): layout.operator("mesh.primitive_n_joint_add", text="Pipe N-Joint") + # Register all operators and panels # Define "Extras" menu def menu_func(self, context): - self.layout.operator("mesh.primitive_polysphere_add", text="Polysphere") - self.layout.menu("INFO_MT_mesh_pipe_joints_add", text="Pipe Joints") - self.layout.menu("INFO_MT_mesh_gears_add", text="Gears") - self.layout.menu("INFO_MT_mesh_math_add", text="Math Function") - self.layout.menu("INFO_MT_mesh_torus_add", text="Torus Objects") - self.layout.menu("INFO_MT_mesh_basic_add", text="Basic Objects") - self.layout.menu("INFO_MT_mesh_misc_add", text="Misc Objects") + self.layout.separator() + self.layout.menu("INFO_MT_mesh_vert_add", text="Single Vert", icon="LAYER_ACTIVE") + self.layout.menu("INFO_MT_mesh_round_cube_add", text="Round Cube", icon="WIRE") + self.layout.menu("INFO_MT_mesh_math_add", text="Math Function", icon="PACKAGE") + self.layout.menu("INFO_MT_mesh_pipe_joints_add", text="Pipe Joints", icon="SNAP_PEEL_OBJECT") + self.layout.menu("INFO_MT_mesh_gears_add", text="Gears", icon="SCRIPTWIN") + self.layout.menu("INFO_MT_mesh_torus_add", text="Torus Objects", icon="MESH_TORUS") + self.layout.menu("INFO_MT_mesh_extras_add", text="Extras", icon="MESH_DATA") + self.layout.separator() + self.layout.operator("object.parent_to_empty", text="Parent To Empty", icon="LINK_AREA") + self.layout.separator() def register(): diff --git a/add_mesh_extra_objects/add_empty_as_parent.py b/add_mesh_extra_objects/add_empty_as_parent.py new file mode 100644 index 00000000..86280554 --- /dev/null +++ b/add_mesh_extra_objects/add_empty_as_parent.py @@ -0,0 +1,57 @@ +# GPL # Original Author Liero # + +import bpy +from bpy.props import StringProperty, FloatProperty, BoolProperty, FloatVectorProperty + +def centro(objetos): + x = sum([obj.location[0] for obj in objetos])/len(objetos) + y = sum([obj.location[1] for obj in objetos])/len(objetos) + z = sum([obj.location[2] for obj in objetos])/len(objetos) + return (x,y,z) + +class P2E(bpy.types.Operator): + bl_idname = 'object.parent_to_empty' + bl_label = 'Parent Selected to Empty' + bl_description = 'Parent selected objects to a new Empty' + bl_options = {'REGISTER', 'UNDO'} + + nombre = StringProperty(name='', default='OBJECTS', description='Give the empty / group a name') + grupo = bpy.props.BoolProperty(name='Create Group', default=False, description='Also link objects to a new group') + cursor = bpy.props.BoolProperty(name='Cursor Location', default=False, description='Add the empty at cursor / selection center') + renombrar = bpy.props.BoolProperty(name='Rename Objects', default=False, description='Rename child objects') + + @classmethod + def poll(cls, context): + return (context.object and context.object.select) + + def draw(self, context): + layout = self.layout + layout.prop(self,'nombre') + column = layout.column(align=True) + column.prop(self,'grupo') + column.prop(self,'cursor') + column.prop(self,'renombrar') + + def execute(self, context): + objs = bpy.context.selected_objects + bpy.ops.object.mode_set() + if self.cursor: + loc = context.scene.cursor_location + else: + loc = centro(objs) + bpy.ops.object.add(type='EMPTY',location=loc) + bpy.context.object.name = self.nombre + if self.grupo: + bpy.ops.group.create(name=self.nombre) + bpy.ops.group.objects_add_active() + for o in objs: + o.select = True + if not o.parent: + bpy.ops.object.parent_set(type='OBJECT') + if self.grupo: + bpy.ops.group.objects_add_active() + o.select = False + for o in objs: + if self.renombrar: + o.name = self.nombre+'_'+o.name + return {'FINISHED'} \ No newline at end of file diff --git a/add_mesh_extra_objects/add_mesh_3d_function_surface.py b/add_mesh_extra_objects/add_mesh_3d_function_surface.py index 1f9d4b14..f91aff6c 100644 --- a/add_mesh_extra_objects/add_mesh_3d_function_surface.py +++ b/add_mesh_extra_objects/add_mesh_3d_function_surface.py @@ -1,25 +1,4 @@ -# ##### BEGIN GPL LICENSE BLOCK ##### -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### -''' - "name": "3D Function Surfaces", - "author": "Buerbaum Martin (Pontiac), Elod Csirmaz", - "version": (0, 3, 8), -''' +# GPL # original by Buerbaum Martin (Pontiac), Elod Csirmaz import bpy from mathutils import * @@ -66,18 +45,7 @@ def create_mesh_object(context, verts, edges, faces, name): # A very simple "bridge" tool. -# Connects two equally long vertex rows with faces. -# Returns a list of the new faces (list of lists) -# -# vertIdx1 ... First vertex list (list of vertex indices). -# vertIdx2 ... Second vertex list (list of vertex indices). -# closed ... Creates a loop (first & last are closed). -# flipped ... Invert the normal of the face(s). -# -# Note: You can set vertIdx1 to a single vertex index to create -# a fan/star of faces. -# Note: If both vertex idx list are the same length they have -# to have at least 2 vertices. + def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False): faces = [] diff --git a/add_mesh_extra_objects/add_mesh_extra_objects.py b/add_mesh_extra_objects/add_mesh_extra_objects.py deleted file mode 100644 index 040e13fe..00000000 --- a/add_mesh_extra_objects/add_mesh_extra_objects.py +++ /dev/null @@ -1,486 +0,0 @@ -# ##### BEGIN GPL LICENSE BLOCK ##### -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -import bpy -from mathutils import * -from math import * -from bpy.props import * - -# Create a new mesh (object) from verts/edges/faces. -# verts/edges/faces ... List of vertices/edges/faces for the -# new mesh (as used in from_pydata). -# name ... Name of the new mesh (& object). -def create_mesh_object(context, verts, edges, faces, name): - - # Create new mesh - mesh = bpy.data.meshes.new(name) - - # Make a mesh from a list of verts/edges/faces. - mesh.from_pydata(verts, edges, faces) - - # Update mesh geometry after adding stuff. - mesh.update() - - from bpy_extras import object_utils - return object_utils.object_data_add(context, mesh, operator=None) - -# A very simple "bridge" tool. -# Connects two equally long vertex rows with faces. -# Returns a list of the new faces (list of lists) -# -# vertIdx1 ... First vertex list (list of vertex indices). -# vertIdx2 ... Second vertex list (list of vertex indices). -# closed ... Creates a loop (first & last are closed). -# flipped ... Invert the normal of the face(s). -# -# Note: You can set vertIdx1 to a single vertex index to create -# a fan/star of faces. -# Note: If both vertex idx list are the same length they have -# to have at least 2 vertices. -def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False): - faces = [] - - if not vertIdx1 or not vertIdx2: - return None - - if len(vertIdx1) < 2 and len(vertIdx2) < 2: - return None - - fan = False - if (len(vertIdx1) != len(vertIdx2)): - if (len(vertIdx1) == 1 and len(vertIdx2) > 1): - fan = True - else: - return None - - total = len(vertIdx2) - - if closed: - # Bridge the start with the end. - if flipped: - face = [ - vertIdx1[0], - vertIdx2[0], - vertIdx2[total - 1]] - if not fan: - face.append(vertIdx1[total - 1]) - faces.append(face) - - else: - face = [vertIdx2[0], vertIdx1[0]] - if not fan: - face.append(vertIdx1[total - 1]) - face.append(vertIdx2[total - 1]) - faces.append(face) - - # Bridge the rest of the faces. - for num in range(total - 1): - if flipped: - if fan: - face = [vertIdx2[num], vertIdx1[0], vertIdx2[num + 1]] - else: - face = [vertIdx2[num], vertIdx1[num], - vertIdx1[num + 1], vertIdx2[num + 1]] - faces.append(face) - else: - if fan: - face = [vertIdx1[0], vertIdx2[num], vertIdx2[num + 1]] - else: - face = [vertIdx1[num], vertIdx2[num], - vertIdx2[num + 1], vertIdx1[num + 1]] - faces.append(face) - - return faces - - -# @todo Clean up vertex&face creation process a bit. -def add_sqorus(hole_size, subdivide): - verts = [] - faces = [] - - size = 2.0 - - thickness = (size - hole_size) / 2.0 - distances = [ - -size / 2.0, - -size / 2.0 + thickness, - size / 2.0 - thickness, - size / 2.0] - - if subdivide: - for i in range(4): - y = distances[i] - - for j in range(4): - x = distances[j] - - verts.append(Vector((x, y, size / 2.0))) - verts.append(Vector((x, y, -size / 2.0))) - - # Top outer loop (vertex indices) - vIdx_out_up = [0, 2, 4, 6, 14, 22, 30, 28, 26, 24, 16, 8] - # Lower outer loop (vertex indices) - vIdx_out_low = [i + 1 for i in vIdx_out_up] - - faces_outside = createFaces(vIdx_out_up, vIdx_out_low, closed=True) - faces.extend(faces_outside) - - # Top inner loop (vertex indices) - vIdx_inner_up = [10, 12, 20, 18] - - # Lower inner loop (vertex indices) - vIdx_inner_low = [i + 1 for i in vIdx_inner_up] - - faces_inside = createFaces(vIdx_inner_up, vIdx_inner_low, - closed=True, flipped=True) - faces.extend(faces_inside) - - row1_top = [0, 8, 16, 24] - row2_top = [i + 2 for i in row1_top] - row3_top = [i + 2 for i in row2_top] - row4_top = [i + 2 for i in row3_top] - - faces_top1 = createFaces(row1_top, row2_top) - faces.extend(faces_top1) - faces_top2_side1 = createFaces(row2_top[:2], row3_top[:2]) - faces.extend(faces_top2_side1) - faces_top2_side2 = createFaces(row2_top[2:], row3_top[2:]) - faces.extend(faces_top2_side2) - faces_top3 = createFaces(row3_top, row4_top) - faces.extend(faces_top3) - - row1_bot = [1, 9, 17, 25] - row2_bot = [i + 2 for i in row1_bot] - row3_bot = [i + 2 for i in row2_bot] - row4_bot = [i + 2 for i in row3_bot] - - faces_bot1 = createFaces(row1_bot, row2_bot, flipped=True) - faces.extend(faces_bot1) - faces_bot2_side1 = createFaces(row2_bot[:2], row3_bot[:2], - flipped=True) - faces.extend(faces_bot2_side1) - faces_bot2_side2 = createFaces(row2_bot[2:], row3_bot[2:], - flipped=True) - faces.extend(faces_bot2_side2) - faces_bot3 = createFaces(row3_bot, row4_bot, flipped=True) - faces.extend(faces_bot3) - - else: - # Do not subdivde outer faces - - vIdx_out_up = [] - vIdx_out_low = [] - vIdx_in_up = [] - vIdx_in_low = [] - - for i in range(4): - y = distances[i] - - for j in range(4): - x = distances[j] - - append = False - inner = False - # Outer - if (i in [0, 3] and j in [0, 3]): - append = True - - # Inner - if (i in [1, 2] and j in [1, 2]): - append = True - inner = True - - if append: - vert_up = len(verts) - verts.append(Vector((x, y, size / 2.0))) - vert_low = len(verts) - verts.append(Vector((x, y, -size / 2.0))) - - if inner: - vIdx_in_up.append(vert_up) - vIdx_in_low.append(vert_low) - - else: - vIdx_out_up.append(vert_up) - vIdx_out_low.append(vert_low) - - # Flip last two vertices - vIdx_out_up = vIdx_out_up[:2] + list(reversed(vIdx_out_up[2:])) - vIdx_out_low = vIdx_out_low[:2] + list(reversed(vIdx_out_low[2:])) - vIdx_in_up = vIdx_in_up[:2] + list(reversed(vIdx_in_up[2:])) - vIdx_in_low = vIdx_in_low[:2] + list(reversed(vIdx_in_low[2:])) - - # Create faces - faces_top = createFaces(vIdx_in_up, vIdx_out_up, closed=True) - faces.extend(faces_top) - faces_bottom = createFaces(vIdx_out_low, vIdx_in_low, closed=True) - faces.extend(faces_bottom) - faces_inside = createFaces(vIdx_in_low, vIdx_in_up, closed=True) - faces.extend(faces_inside) - faces_outside = createFaces(vIdx_out_up, vIdx_out_low, closed=True) - faces.extend(faces_outside) - - return verts, faces - - -def add_wedge(size_x, size_y, size_z): - verts = [] - faces = [] - - size_x /= 2.0 - size_y /= 2.0 - size_z /= 2.0 - - vIdx_top = [] - vIdx_bot = [] - - vIdx_top.append(len(verts)) - verts.append(Vector((-size_x, -size_y, size_z))) - vIdx_bot.append(len(verts)) - verts.append(Vector((-size_x, -size_y, -size_z))) - - vIdx_top.append(len(verts)) - verts.append(Vector((size_x, -size_y, size_z))) - vIdx_bot.append(len(verts)) - verts.append(Vector((size_x, -size_y, -size_z))) - - vIdx_top.append(len(verts)) - verts.append(Vector((-size_x, size_y, size_z))) - vIdx_bot.append(len(verts)) - verts.append(Vector((-size_x, size_y, -size_z))) - - faces.append(vIdx_top) - faces.append(vIdx_bot) - faces_outside = createFaces(vIdx_top, vIdx_bot, closed=True) - faces.extend(faces_outside) - - return verts, faces - -def add_star(points, outer_radius, inner_radius, height): - PI_2 = pi * 2 - z_axis = (0, 0, 1) - - verts = [] - faces = [] - - segments = points * 2 - - half_height = height / 2.0 - - vert_idx_top = len(verts) - verts.append(Vector((0.0, 0.0, half_height))) - - vert_idx_bottom = len(verts) - verts.append(Vector((0.0, 0.0, -half_height))) - - edgeloop_top = [] - edgeloop_bottom = [] - - for index in range(segments): - quat = Quaternion(z_axis, (index / segments) * PI_2) - - if index % 2: - # Uneven - radius = outer_radius - else: - # Even - radius = inner_radius - - edgeloop_top.append(len(verts)) - vec = quat * Vector((radius, 0, half_height)) - verts.append(vec) - - edgeloop_bottom.append(len(verts)) - vec = quat * Vector((radius, 0, -half_height)) - verts.append(vec) - - - - faces_top = createFaces([vert_idx_top], edgeloop_top, closed=True) - faces_outside = createFaces(edgeloop_top, edgeloop_bottom, closed=True) - faces_bottom = createFaces([vert_idx_bottom], edgeloop_bottom, - flipped=True, closed=True) - - faces.extend(faces_top) - faces.extend(faces_outside) - faces.extend(faces_bottom) - - return verts, faces - -def trapezohedron(s,r,h): - """ - s = segments - r = base radius - h = tip height - """ - - # calculate constants - a = 2*pi/(2*s) # angle between points along the equator - l = r*cos(a) # helper for e - e = h*(r-l)/(l+r) # the z offset for each vector along the equator so faces are planar - - # rotation for the points - quat = Quaternion((0,0,1),a) - - # first 3 vectors, every next one is calculated from the last, and the z-value is negated - verts = [Vector(i) for i in [(0,0,h),(0,0,-h),(r,0,e)]] - for i in range(2*s-1): - verts.append(quat*verts[-1]) # rotate further "a" radians around the z-axis - verts[-1].z *= -1 # negate last z-value to account for the zigzag - - faces = [] - for i in range(2,2+2*s,2): - n = [i+1,i+2,i+3] # vertices in current section - for j in range(3): # check whether the numbers dont go over len(verts) - if n[j]>=2*s+2: n[j]-=2*s # if so, subtract len(verts)-2 - - # add faces of current section - faces.append([0,i]+n[:2]) - faces.append([1,n[2],n[1],n[0]]) - - return verts,faces - -class AddSqorus(bpy.types.Operator): - """Add a sqorus mesh""" - bl_idname = "mesh.primitive_sqorus_add" - bl_label = "Add Sqorus" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} - - hole_size = FloatProperty(name="Hole Size", - description="Size of the Hole", - min=0.01, - max=1.99, - default=2.0 / 3.0) - subdivide = BoolProperty(name="Subdivide Outside", - description="Enable to subdivide the faces on the outside " \ - "(this results in equally spaced vertices)", - default=True) - - def execute(self, context): - - # Create mesh geometry - verts, faces = add_sqorus( - self.hole_size, - self.subdivide) - - # Create mesh object (and meshdata) - obj = create_mesh_object(context, verts, [], faces, "Sqorus") - - return {'FINISHED'} - - -class AddWedge(bpy.types.Operator): - """Add a wedge mesh""" - bl_idname = "mesh.primitive_wedge_add" - bl_label = "Add Wedge" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} - - size_x = FloatProperty(name="Size X", - description="Size along the X axis", - min=0.01, - max=9999.0, - default=2.0) - size_y = FloatProperty(name="Size Y", - description="Size along the Y axis", - min=0.01, - max=9999.0, - default=2.0) - size_z = FloatProperty(name="Size Z", - description="Size along the Z axis", - min=0.01, - max=9999.0, - default=2.00) - - def execute(self, context): - - verts, faces = add_wedge( - self.size_x, - self.size_y, - self.size_z) - - obj = create_mesh_object(context, verts, [], faces, "Wedge") - - return {'FINISHED'} - - -class AddStar(bpy.types.Operator): - """Add a star mesh""" - bl_idname = "mesh.primitive_star_add" - bl_label = "Add Star" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} - - points = IntProperty(name="Points", - description="Number of points for the star", - min=2, - max=256, - default=5) - outer_radius = FloatProperty(name="Outer Radius", - description="Outer radius of the star", - min=0.01, - max=9999.0, - default=1.0) - innter_radius = FloatProperty(name="Inner Radius", - description="Inner radius of the star", - min=0.01, - max=9999.0, - default=0.5) - height = FloatProperty(name="Height", - description="Height of the star", - min=0.01, - max=9999.0, - default=0.5) - - def execute(self, context): - - verts, faces = add_star( - self.points, - self.outer_radius, - self.innter_radius, - self.height) - - obj = create_mesh_object(context, verts, [], faces, "Star") - - return {'FINISHED'} - - -class AddTrapezohedron(bpy.types.Operator): - """Add a trapezohedron""" - bl_idname = "mesh.primitive_trapezohedron_add" - bl_label = "Add trapezohedron" - bl_description = "Create one of the regular solids" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} - - segments = IntProperty(name = "Segments", - description = "Number of repeated segments", - default = 4, min = 2, max = 256) - radius = FloatProperty(name = "Base radius", - description = "Radius of the middle", - default = 1.0, min = 0.01, max = 100.0) - height = FloatProperty(name = "Tip height", - description = "Height of the tip", - default = 1, min = 0.01, max = 100.0) - - def execute(self,context): - # generate mesh - verts,faces = trapezohedron(self.segments, - self.radius, - self.height) - - obj = create_mesh_object(context, verts, [], faces, "Trapazohedron") - - return {'FINISHED'} diff --git a/add_mesh_extra_objects/add_mesh_gears.py b/add_mesh_extra_objects/add_mesh_gears.py index e7196f69..0518e659 100644 --- a/add_mesh_extra_objects/add_mesh_gears.py +++ b/add_mesh_extra_objects/add_mesh_gears.py @@ -1,28 +1,4 @@ -# add_mesh_gear.py (c) 2009, 2010 Michel J. Anders (varkenvarken) -# -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ***** END GPL LICENCE BLOCK ***** -''' - "name": "Gears", - "author": "Michel J. Anders (varkenvarken)", - "version": (2, 4, 2), -''' +# GPL # (c) 2009, 2010 Michel J. Anders (varkenvarken) import bpy from math import * @@ -58,6 +34,7 @@ def create_mesh_object(context, verts, edges, faces, name): # a fan/star of faces. # Note: If both vertex idx list are the same length they have # to have at least 2 vertices. + def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False): faces = [] diff --git a/add_mesh_extra_objects/add_mesh_gemstones.py b/add_mesh_extra_objects/add_mesh_gemstones.py index 5d4f83ca..e6b4b67b 100644 --- a/add_mesh_extra_objects/add_mesh_gemstones.py +++ b/add_mesh_extra_objects/add_mesh_gemstones.py @@ -1,25 +1,5 @@ -# ##### BEGIN GPL LICENSE BLOCK ##### -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### -''' - "name": "Gemstones", - "author": "Pontiac, Fourmadmen, Dreampainter", - "version": (0, 4), -''' +# GPL # "author": "Pontiac, Fourmadmen, Dreampainter" + import bpy from mathutils import * from math import * @@ -44,18 +24,7 @@ def create_mesh_object(context, verts, edges, faces, name): return object_utils.object_data_add(context, mesh, operator=None) # A very simple "bridge" tool. -# Connects two equally long vertex rows with faces. -# Returns a list of the new faces (list of lists) -# -# vertIdx1 ... First vertex list (list of vertex indices). -# vertIdx2 ... Second vertex list (list of vertex indices). -# closed ... Creates a loop (first & last are closed). -# flipped ... Invert the normal of the face(s). -# -# Note: You can set vertIdx1 to a single vertex index to create -# a fan/star of faces. -# Note: If both vertex idx list are the same length they have -# to have at least 2 vertices. + def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False): faces = [] diff --git a/add_mesh_extra_objects/add_mesh_honeycomb.py b/add_mesh_extra_objects/add_mesh_honeycomb.py index 53194f28..df60671b 100644 --- a/add_mesh_extra_objects/add_mesh_honeycomb.py +++ b/add_mesh_extra_objects/add_mesh_honeycomb.py @@ -1,25 +1,5 @@ -# ##### BEGIN GPL LICENSE BLOCK ##### -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### -''' - "name": "HoneyComb", - "author": "Kayo Phoenix ", - "version": (0, 1), -''' +# GPL # "author": "Kayo Phoenix" + from math import pi, sin, cos class honeycomb_geometry(): @@ -256,20 +236,3 @@ class add_mesh_honeycomb(bpy.types.Operator): object_utils.object_data_add(context, mesh, operator=self) return {'FINISHED'} -''' -def menu_func(self, context): - self.layout.operator(add_mesh_honeycomb.bl_idname, text = bl_info['name'], icon="PLUGIN") - -def register(): - bpy.utils.register_module(__name__) - - bpy.types.INFO_MT_mesh_add.append(menu_func) - -def unregister(): - bpy.utils.unregister_module(__name__) - - bpy.types.INFO_MT_mesh_add.remove(menu_func) - -if __name__ == "__main__": - register() -''' diff --git a/add_mesh_extra_objects/add_mesh_menger_sponge.py b/add_mesh_extra_objects/add_mesh_menger_sponge.py new file mode 100644 index 00000000..43c8c57d --- /dev/null +++ b/add_mesh_extra_objects/add_mesh_menger_sponge.py @@ -0,0 +1,185 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2015 sugiany +# This file is distributed under the MIT License. See the LICENSE.md for more details. + +import bpy + +from bpy.props import IntProperty, BoolProperty, FloatVectorProperty, FloatProperty + +import bpy +import mathutils +import copy + +class MengerSponge(object): + FACE_INDICES = [ + [3, 7, 4, 0], + [5, 6, 2, 1], + [1, 2, 3, 0], + [7, 6, 5, 4], + [4, 5, 1, 0], + [2, 6, 7, 3], + ] + + def __init__(self, level): + self.__level = level + self.__max_point_number = 3 ** level + self.__vertices_map = {} + self.__indices = [] + self.__face_visibility = {} + self.__faces = [] + + for x in range(3): + for y in range(3): + for z in range(3): + self.__face_visibility[(x, y, z)] = [ + x == 0 or x == 2 and (y == 1 or z == 1), + x == 2 or x == 0 and (y == 1 or z == 1), + y == 0 or y == 2 and (x == 1 or z == 1), + y == 2 or y == 0 and (x == 1 or z == 1), + z == 0 or z == 2 and (y == 1 or x == 1), + z == 2 or z == 0 and (y == 1 or x == 1), + ] + + def create(self, width, height): + m = self.__max_point_number + points = [ + (0, 0, 0), + (m, 0, 0), + (m, 0, m), + (0, 0, m), + (0, m, 0), + (m, m, 0), + (m, m, m), + (0, m, m), + ] + self.__make_sub_sponge(points, None, self.__level) + vertices = self.__make_vertices(width, height) + return vertices, self.__faces + + def __get_vindex(self, p): + if p in self.__vertices_map: + return self.__vertices_map[p] + index = len(self.__vertices_map) + self.__vertices_map[p] = index + return index + + def __make_vertices(self, width, height): + vertices = [None] * len(self.__vertices_map) + w2 = width / 2 + h2 = height / 2 + w_step = width / self.__max_point_number + h_step = height / self.__max_point_number + for p, i in sorted(self.__vertices_map.items(), key=lambda x: x[1]): + vertices[i] = mathutils.Vector([ + p[0] * w_step - w2, + p[1] * w_step - w2, + p[2] * h_step - h2, + ]) + return vertices + + def __make_sub_sponge(self, cur_points, face_vis, depth): + if depth <= 0: + if not face_vis: + face_vis = True * 6 + cur_point_indices = [] + for p in cur_points: + cur_point_indices.append(self.__get_vindex(p)) + for i, vis in enumerate(face_vis): + if vis: + f = [] + for vi in self.FACE_INDICES[i]: + f.append(cur_point_indices[vi]) + self.__faces.append(f) + return + + base = cur_points[0] + width = (cur_points[1][0] - base[0]) / 3 + local_vert_map = {} + for z in range(4): + for y in range(4): + for x in range(4): + local_vert_map[(x, y, z)] = ( + width * x + base[0], + width * y + base[1], + width * z + base[2], + ) + + for x in range(3): + for y in range(3): + for z in range(3): + if [x, y, z].count(1) > 1: + continue + next_points = [ + local_vert_map[(x, y, z)], + local_vert_map[(x+1, y, z)], + local_vert_map[(x+1, y, z+1)], + local_vert_map[(x, y, z+1)], + local_vert_map[(x, y+1, z)], + local_vert_map[(x+1, y+1, z)], + local_vert_map[(x+1, y+1, z+1)], + local_vert_map[(x, y+1, z+1)], + ] + visibility = copy.copy(self.__face_visibility[(x, y, z)]) + if face_vis: + visibility[0] = visibility[0] and (face_vis[0] or x != 0) + visibility[1] = visibility[1] and (face_vis[1] or x != 2) + visibility[2] = visibility[2] and (face_vis[2] or y != 0) + visibility[3] = visibility[3] and (face_vis[3] or y != 2) + visibility[4] = visibility[4] and (face_vis[4] or z != 0) + visibility[5] = visibility[5] and (face_vis[5] or z != 2) + self.__make_sub_sponge( + next_points, + visibility, + depth - 1) + + +class AddMengerSponge(bpy.types.Operator): + """Add a menger sponge""" + bl_idname = "mesh.menger_sponge_add" + bl_label = "Menger Sponge" + bl_options = {'REGISTER', 'UNDO'} + + level = IntProperty( + name="Level", + description="Sponge Level", + min=0, max=4, + default=1, + ) + + radius = FloatProperty( + name="Width", + description="Sponge Radius", + min=0.01, max=100.0, + default=1.0, + ) + + # generic transform props + view_align = BoolProperty( + name="Align to View", + default=False, + ) + location = FloatVectorProperty( + name="Location", + subtype='TRANSLATION', + ) + rotation = FloatVectorProperty( + name="Rotation", + subtype='EULER', + ) + + def execute(self, context): + sponger = MengerSponge(self.level) + vertices, faces = sponger.create(self.radius * 2, self.radius * 2) + del sponger + + mesh = bpy.data.meshes.new(name='Sponge') + mesh.from_pydata(vertices, [], faces) + uvs = [(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)] + mesh.uv_textures.new() + for i, uvloop in enumerate(mesh.uv_layers.active.data): + uvloop.uv = uvs[i%4] + + from bpy_extras import object_utils + object_utils.object_data_add(context, mesh, operator=self) + + return {'FINISHED'} diff --git a/add_mesh_extra_objects/add_mesh_pipe_joint.py b/add_mesh_extra_objects/add_mesh_pipe_joint.py index e0dcc3e8..85899cd3 100644 --- a/add_mesh_extra_objects/add_mesh_pipe_joint.py +++ b/add_mesh_extra_objects/add_mesh_pipe_joint.py @@ -1,25 +1,5 @@ -# ##### BEGIN GPL LICENSE BLOCK ##### -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### -''' - "name": "Pipe Joints", - "author": "Buerbaum Martin (Pontiac)", - "version": (0, 10, 7), -''' +# GPL # "author": "Buerbaum Martin (Pontiac)" + import bpy from math import * from bpy.props import * @@ -42,18 +22,7 @@ def create_mesh_object(context, verts, edges, faces, name): return object_utils.object_data_add(context, mesh, operator=None) # A very simple "bridge" tool. -# Connects two equally long vertex rows with faces. -# Returns a list of the new faces (list of lists) -# -# vertIdx1 ... First vertex list (list of vertex indices). -# vertIdx2 ... Second vertex list (list of vertex indices). -# closed ... Creates a loop (first & last are closed). -# flipped ... Invert the normal of the face(s). -# -# Note: You can set vertIdx1 to a single vertex index to create -# a fan/star of faces. -# Note: If both vertex idx list are the same length they have -# to have at least 2 vertices. + def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False): faces = [] @@ -988,5 +957,3 @@ class AddNJoint(bpy.types.Operator): base = create_mesh_object(context, verts, [], faces, "N Joint") return {'FINISHED'} - -################################ \ No newline at end of file diff --git a/add_mesh_extra_objects/add_mesh_polysphere.py b/add_mesh_extra_objects/add_mesh_polysphere.py deleted file mode 100644 index b01e741a..00000000 --- a/add_mesh_extra_objects/add_mesh_polysphere.py +++ /dev/null @@ -1,79 +0,0 @@ -# ##### BEGIN GPL LICENSE BLOCK ##### -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### -''' - "name": "Add PolySphere", - "author": "Andy Davies (metalliandy)", - "version": (0,1,6), -''' - -import bpy - -def Add_PolySphere(): - #Add Cube to scene - bpy.ops.mesh.primitive_cube_add() - - #Changes name of Cube to PolySphere adds the variable cube - cube = bpy.context.object - cube.name = "PolySphere" - - #Positions Cube primitive to scene centre - bpy.context.active_object.location = [0, 0, 0] - - #Adds Subsurf Modifier - bpy.ops.object.modifier_add(type='SUBSURF') - - #Selects Subsurf Modifier for editing - subsurf = cube.modifiers['Subsurf'] - - #Changes Subsurf levels - subsurf.levels = 3 - - #Applys Subsurf Modifier - bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Subsurf") - - #Adds smooth shading - bpy.ops.object.shade_smooth() - - #Change to Editmode - bpy.ops.object.editmode_toggle() - - #Selects cube in Editmode - #bpy.ops.mesh.select_all(action='TOGGLE') - - #Adds transform "To Sphere" - bpy.ops.transform.tosphere(value=1) - - #Change to Objectmode - bpy.ops.object.editmode_toggle() - - #Scales Object to 2.0 Units - bpy.ops.transform.resize(value=(1.15525, 1.15525, 1.15525), constraint_axis=(False, False, False), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1, snap=False, snap_target='CLOSEST', snap_point=(0, 0, 0), snap_align=False, snap_normal=(0, 0, 0), release_confirm=False) - - #Applys location, rotation and scale data - bpy.ops.object.transform_apply(location=True, rotation=True, scale=True) - -#makes PolySphere an operator -class AddPolySphere(bpy.types.Operator): - - bl_idname = "mesh.primitive_polysphere_add" - bl_label = "Add PolySphere" - bl_options = {'REGISTER', 'UNDO'} - - def execute(self, context): - Add_PolySphere() - return {'FINISHED'} diff --git a/add_mesh_extra_objects/add_mesh_pyramid.py b/add_mesh_extra_objects/add_mesh_pyramid.py index 8ca68503..0876af11 100644 --- a/add_mesh_extra_objects/add_mesh_pyramid.py +++ b/add_mesh_extra_objects/add_mesh_pyramid.py @@ -1,35 +1,4 @@ -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ***** END GPL LICENCE BLOCK ***** - -# (c) 2011 Phil Cote (cotejrp1) -''' -bl_info = { - "name": "Mesh Pyramid", - "author": "Phil Cote, cotejrp1, (http://www.blenderaddons.com)", - "version": (0, 5), - "blender": (2, 63, 0), - "location": "View3D > Add > Mesh", - "description": "Create an egyption-style step pyramid", - "warning": "", # used for warning icon and text in addons panel - "category": "Add Mesh", -} -''' +# GPL # "author": "Phil Cote, cotejrp1, (http://www.blenderaddons.com)" import bpy import bmesh @@ -163,21 +132,3 @@ class AddPyramid(bpy.types.Operator, AddObjectHelper): def execute(self, context): add_pyramid_object(self, context) return {'FINISHED'} - -''' -def menu_func(self, context): - self.layout.operator(AddPyramid.bl_idname, icon='PLUGIN') - - -def register(): - bpy.utils.register_class(AddPyramid) - bpy.types.INFO_MT_mesh_add.append(menu_func) - - -def unregister(): - bpy.utils.unregister_class(AddPyramid) - bpy.types.INFO_MT_mesh_add.remove(menu_func) - -if __name__ == "__main__": - register() -''' diff --git a/add_mesh_extra_objects/add_mesh_round_brilliant.py b/add_mesh_extra_objects/add_mesh_round_brilliant.py new file mode 100644 index 00000000..ea544818 --- /dev/null +++ b/add_mesh_extra_objects/add_mesh_round_brilliant.py @@ -0,0 +1,365 @@ +# GPL "author": "Dominic Kröper, (dommetysk)" + +import bpy +from math import pi, sin, cos, tan +from bpy.types import Operator +from bpy.props import IntProperty, FloatProperty, BoolProperty +from mathutils import Vector, Euler + +# mesh/object generating function, returns final object +def addBrilliant(context, s, table_w, crown_h, girdle_t, pavi_d, bezel_f, + pavi_f, culet, girdle_real, keep_lga, g_real_smooth): + +# # possible user inputs ( output 100% = 2 blender units ) +# s # no. of girdle facets (steps) default: 16 +# table_w # table width default: 0.530 +# crown_h # crown height default: 0.162 +# girdle_t # girdle thickness default: 0.017 +# pavi_d # pavillion depth default: 0.431 +# bezel_f # bezel factor default: 0.250 +# pavi_f # pavillion factor default: 0.400 +# culet # culet size default: 0.000 +# girdle_real # type of girdle flat/real default: True +# g_real_smooth # smooth or flat shading default: False +# keep_lga # when culet > 0, keep lga default: False + + # variables / shortcuts + if s % 2: # prevent odd number of steps (messes up mesh) + s = s - 1 + if not girdle_real: + g_real_smooth = False + ang = 2*pi/s # angle step size + Verts = [] # collect all vertices + Faces = [] # collect all faces + ca = cos(ang) + ca2 = cos(ang/2) + sa4 = sin(ang/4) + ta4 = tan(ang/4) + ta8 = tan(ang/8) + + def fa(*vs): # shortcut Faces.append + v = [] + for u in vs: + v.append(u) + Faces.append(v) + + def va(vx, vz, iang, sang, n): # shortcut Verts.append + for i in range(n): + v = Vector((vx, 0, vz)) + ai = sang + iang*i + E_rot = Euler((0, 0, ai), 'XYZ') + v.rotate(E_rot) + Verts.append((v.x, v.y, v.z)) + + + # upper girdle angle + uga = (1-bezel_f) * crown_h*2 / (ca2 - + (table_w + (1-table_w) * bezel_f) * ca2/ca) + + # lower girdle angle + if keep_lga: + if pavi_f > 0 and pavi_f < 1: + lga = (1-pavi_f) * pavi_d*2 / (ca2 - pavi_f*ca2 / ca) + elif pavi_f == 1: + lga = 0 + else: + lga = 2*pavi_d*ca + else: + lga = (1-pavi_f) * pavi_d*2 / (ca2 - + (culet + (1-culet) * pavi_f) * ca2/ca) + + # append girdle vertices + va(1, 0, ang, 0, s) + va(1, 2*girdle_t, ang, 0, s) + + # append real girdle vertices + if girdle_real: + dnu = uga * (1 - ca2) + dfu = uga * (ta8 + ta4) * sa4 + dnl = lga * (1 - ca2) + dfl = lga * (ta8 + ta4) * sa4 + if abs(dnu) + abs(dnl) > 2*girdle_t or dnu < 0 or dnl < 0: + girdle_real = False + else: + va(1, dnl, ang, ang/2, s) + va(1, 2*girdle_t - dnu, ang, ang/2, s) + va(1, dfl, ang/2, ang/4, 2*s) + va(1, 2*girdle_t - dfu, ang/2, ang/4, 2*s) + + # make girdle faces + l1 = len(Verts) # 2*s / 8*s + for i in range(l1): + if girdle_real: + if i < s: + fa(i, i + s, 2*i + 6*s, 2*i + 4*s) + if i == 0: + fa(i, s, l1 - 1, 6*s - 1) + else: + fa(i, i + s, 2*i + 6*s - 1, 2*i + 4*s - 1) + elif i > 2*s - 1 and i < 3*s: + fa(i, i + s, 2 * (i+s), 2*i) + fa(i, i + s, 2 * (i+s) + 1, 2*i + 1) + else: + if i < s - 1: + fa(i, i + s, i + s + 1, i + 1) + elif i == s - 1: + fa(i, i + s, s, 0) + + # append upper girdle facet vertices + va((table_w + (1-table_w) * bezel_f) / ca, (1-bezel_f) * 2*crown_h + + 2*girdle_t, 2*ang, ang, int(s/2)) + + # make upper girdle facet faces + l2 = len(Verts) # 2.5*s / 8.5*s + for i in range(l2): + if i > s and i < 2*s - 1 and i % 2 != 0: + if girdle_real: + fa(i, 2 * (i + 2*s), i + 2*s, 2 * (i + 2*s) + 1, i + 1, + int(7.5*s) + int((i-1) / 2)) + fa(i, 2 * (i + 2*s) - 1, i + 2*s - 1, 2 * (i + 2*s - 1), + i - 1, int(7.5*s) + int((i-1) / 2)) + else: + fa(i, i + 1, int((i + 3*s) / 2)) + fa(i, i - 1, int((i + 3*s) / 2)) + elif i == s: + if girdle_real: + fa(i, l1 - 1, 4*s - 1, l1 - 2, 2*i - 1, l2 - 1) + fa(2*i - 2, l1 - 4, 4*s - 2, l1 - 3, 2*i - 1, l2 - 1) + else: + fa(i, 2*i - 1, l2 - 1) + fa(2*i - 1, 2*i - 2, l2 - 1) + + # append table vertices + va(table_w, (crown_h + girdle_t)*2, 2*ang, 0, int(s/2)) + + # make bezel facet faces and star facet faces + l3 = len(Verts) # 3*s / 9*s + for i in range(l3): + if i > l2 - 1 and i < l3 - 1: + fa(i, i + 1, i - int(s/2)) + fa(i + 1, i - int(s/2), 2 * (i-l2) + 2 + s, i - int(s/2) + 1) + elif i == l3 - 1: + fa(i, l2, l2 - 1) + fa(s, l2 - 1, l2, l2 - int(s/2)) + + # make table facet face + tf = [] + for i in range(l3): + if i > l2 - 1: + tf.append(i) + fa(*tf) + + # append lower girdle facet vertices + if keep_lga: + va(pavi_f/ca, (pavi_f-1) * pavi_d*2, 2*ang, ang, int(s/2)) + else: + va((pavi_f * (1-culet) + culet) / ca, (pavi_f-1) * pavi_d*2, 2*ang, + ang, int(s/2)) + + # make lower girdle facet faces + l4 = len(Verts) # 3.5*s / 9.5*s + for i in range(l4): + if i > 0 and i < s - 1 and i % 2 == 0: + if girdle_real: + fa(i, 2 * (i + 2*s), i + 2*s, 2 * (i + 2*s) + 1, i + 1, + int(i/2) + 9*s) + fa(i, 2 * (i + 2*s) - 1, i + 2*s - 1, 2 * (i + 2*s - 1), + i-1, int(i/2) + 9*s - 1) + else: + fa(i, i + 1, int(i/2) + l4 - int(s/2)) + fa(i, i - 1, int(i/2) + l4 - int(s/2) - 1) + elif i == 0: + if girdle_real: + fa(0, 4*s, 2*s, 4*s + 1, 1, 9*s) + fa(0, 6*s - 1, 3*s - 1, 6*s - 2, s - 1, l4 - 1) + else: + fa(0, 1, l4 - int(s/2)) + fa(0, s - 1, l4 - 1) + + # append culet vertice(s) + if culet == 0: + va(0, pavi_d*(-2), 0, 0, 1) + else: + if keep_lga: + va(culet * pavi_f / ca, pavi_d*(-2) + culet * pavi_f * 2 * pavi_d, + 2*ang, ang, int(s/2)) + else: + va(culet/ca, pavi_d*(-2), 2*ang, ang, int(s/2)) + + # make pavillion facet face + l5 = len(Verts) # 4*s / 10*s //if !culet: 3.5*s+1 / 9.5*s+1 + for i in range(l5): + if i > 0 and i < s - 1 and i % 2 == 0: + if culet: + fa(i, l3 + int(i/2), l3 + int((s+i) / 2), + l3 + int((s+i) / 2) - 1, l3 + int(i/2) - 1) + else: + fa(i, l3 + int(i/2), l5 - 1, l3 + int(i/2) - 1) + elif i == 0: + if culet: + fa(i, l3, l4, l5 - 1, l4 - 1) + else: + fa(i, l3, l5 - 1, l4 - 1) + + # make culet facet face + if culet: + cf = [] + for i in range(l5): + if i > l4 - 1: + cf.append(i) + fa(*cf) + + # bpy variables / shortcuts + scene = bpy.context.scene + + # deactivate possible active Objects + bpy.context.scene.objects.active = None + + # create actual mesh and object based on Verts and Faces given + dmesh = bpy.data.meshes.new("dmesh") + dmesh.from_pydata(Verts, [], Faces) + dmesh.update() + dobj = bpy.data.objects.new("dobj", dmesh) + + # link object into scene + scene.objects.link(dobj) + + # activate and select object + scene.objects.active = dobj + dobj.select = True + obj = bpy.context.active_object + + # flip all face normals outside + bpy.ops.object.mode_set(mode='EDIT', toggle=False) + sel_mode = bpy.context.tool_settings.mesh_select_mode + bpy.context.tool_settings.mesh_select_mode = [False, False, True] + bpy.ops.object.mode_set(mode='OBJECT', toggle=False) + for i, face in enumerate(obj.data.polygons): + face.select = True + bpy.ops.object.mode_set(mode='EDIT', toggle=False) + bpy.ops.mesh.normals_make_consistent(inside=False) + bpy.context.tool_settings.mesh_select_mode = sel_mode + bpy.ops.object.mode_set(mode='OBJECT', toggle=False) + + # make girdle smooth for complex girdle + if girdle_real and g_real_smooth: + + bpy.ops.object.mode_set(mode='EDIT', toggle=False) + + bpy.ops.mesh.select_all(action='DESELECT') # deselect all mesh data + bpy.ops.object.mode_set(mode='OBJECT') + pls = [] + dp = obj.data.polygons[:4*s] # only consider faces of girdle + ov = obj.data.vertices + + for i, p in enumerate(dp): + pls.extend(p.vertices) # list all verts of girdle + + for i, e in enumerate(obj.data.edges): # select egdes to mark sharp + if e.vertices[0] in pls and e.vertices[1] in pls and abs( + ov[e.vertices[0]].co.x - ov[e.vertices[1]].co.x): + obj.data.edges[i].select = True + continue + obj.data.edges[i].select = False + + bpy.ops.object.mode_set(mode='EDIT', toggle=False) + bpy.ops.mesh.mark_sharp() + + bpy.context.tool_settings.mesh_select_mode = [False, False, True] + bpy.ops.object.mode_set(mode='OBJECT', toggle=False) + bpy.ops.object.select_all(action='DESELECT') + for i, face in enumerate(obj.data.polygons): + if i < 4*s: + face.select = True + continue + face.select = False + bpy.ops.object.mode_set(mode='EDIT', toggle=False) + bpy.ops.mesh.faces_shade_smooth() + + bpy.ops.object.modifier_add(type='EDGE_SPLIT') + + bpy.context.tool_settings.mesh_select_mode = sel_mode + bpy.ops.object.mode_set(mode='OBJECT', toggle=False) + + bpy.ops.object.modifier_apply(apply_as='DATA', modifier="EdgeSplit") + + + return dobj + + +# add new operator for object +class MESH_OT_primitive_brilliant_add(bpy.types.Operator): + bl_idname = "mesh.primitive_brilliant_add" + bl_label = "Custom Brilliant" + bl_options = {'REGISTER', 'UNDO', 'PRESET'} + + # set user options + s = IntProperty(name="Segments", + description="Longitudial segmentation", + step=1, + min=6, + max=128, + default=16, + subtype='FACTOR') + table_w = FloatProperty(name="Table width", + description="Width of table", + min=0.001, + max=1.0, + default=0.53, + subtype='PERCENTAGE') + crown_h = FloatProperty(name="Crown height", + description="Heigth of crown", + min=0.0, + max=1.0, + default=0.162, + subtype='PERCENTAGE') + girdle_t = FloatProperty(name="Girdle height", + description="Height of girdle", + min=0.0, + max=0.5, + default=0.017, + subtype='PERCENTAGE') + girdle_real = BoolProperty(name="Real girdle", + description="More beautiful girdle; has more polygons", + default=True) + g_real_smooth = BoolProperty(name="Smooth girdle", + description= + "smooth shading for girdle, only available for real girdle", + default=False) + pavi_d = FloatProperty(name="Pavilion depth", + description="Height of pavillion", + min=0.0, + max=1.0, + default=0.431, + subtype='PERCENTAGE') + bezel_f = FloatProperty(name="Upper facet factor", + description= + "Determines the form of bezel and upper girdle facets", + min=0.0, + max=1.0, + default=0.250, + subtype='PERCENTAGE') + pavi_f = FloatProperty(name="Lower facet factor", + description= + "Determines the form of pavillion and lower girdle facets", + min=0.001, + max=1.0, + default=0.400, + subtype='PERCENTAGE') + culet = FloatProperty(name="Culet size", + description="0: no culet (default)", + min=0.0, + max=0.999, + default=0.0, + subtype='PERCENTAGE') + keep_lga = BoolProperty(name="Retain lower angle", + description="If culet > 0, retains angle of pavillion facets", + default=False) + + # call mesh/object generator function with user inputs + def execute(self, context): + ob = addBrilliant(context, self.s, self.table_w, self.crown_h, + self.girdle_t, self.pavi_d, self.bezel_f, + self.pavi_f, self.culet, self.girdle_real, + self.keep_lga, self.g_real_smooth) + return {'FINISHED'} diff --git a/add_mesh_extra_objects/add_mesh_round_cube.py b/add_mesh_extra_objects/add_mesh_round_cube.py new file mode 100644 index 00000000..1c677216 --- /dev/null +++ b/add_mesh_extra_objects/add_mesh_round_cube.py @@ -0,0 +1,479 @@ +# GPL # 'author': 'Alain Ducharme (Phymec)' + +import bpy +from bpy_extras import object_utils +from itertools import permutations +from math import copysign, pi, sqrt + +def round_cube(radius=1.0, arcdiv=4, lindiv=0., size=(0. ,0. ,0.), div_type='CORNERS', odd_axis_align=False, info_only=False): + # subdiv bitmasks + CORNERS, EDGES, ALL = 0, 1, 2 + try: + subdiv = ('CORNERS', 'EDGES', 'ALL').index(div_type) + except ValueError: + subdiv = CORNERS # fallback + + radius = max(radius, 0.) + if not radius: + arcdiv = 1 + + if arcdiv <= 0: + arcdiv = max(round(pi * radius * lindiv * 0.5), 1) + arcdiv = max(round(arcdiv), 1) + if lindiv <= 0.: + if radius: + lindiv = 1. / (pi / (arcdiv * 2.) * radius) + lindiv = max(lindiv, 0.) + if not lindiv: + subdiv = CORNERS + + odd = arcdiv % 2 # even = arcdiv % 2 ^ 1 + step_size = 2. / arcdiv + + odd_aligned = 0 + vi = -1. + steps = arcdiv + 1 + if odd_axis_align and odd: + odd_aligned = 1 + vi += 0.5 * step_size + steps = arcdiv + axis_aligned = not odd or odd_aligned + + if arcdiv == 1 and not odd_aligned and subdiv == EDGES: + subdiv = CORNERS + + half_chord = 0. # ~ spherical cap base radius + sagitta = 0. # ~ spherical cap height + if not axis_aligned: + half_chord = sqrt(3.) * radius / (3. * arcdiv) + id2 = 1. / (arcdiv * arcdiv) + sagitta = radius - radius * sqrt(id2 * id2 / 3. - id2 + 1.) + + # Extrusion per axis + exyz = [0. if s < 2. * (radius - sagitta) else (s - 2. * (radius - sagitta)) * 0.5 for s in size] + ex, ey, ez = exyz + + dxyz = [0, 0, 0] # extrusion divisions per axis + dssxyz = [0., 0., 0.] # extrusion division step sizes per axis + + for i in range(3): + sc = 2. * (exyz[i] + half_chord) + dxyz[i] = round(sc * lindiv) if subdiv else 0 + if dxyz[i]: + dssxyz[i] = sc / dxyz[i] + dxyz[i] -= 1 + else: + dssxyz[i] = sc + + if info_only: + ec = sum(1 for n in exyz if n) + if subdiv: + fxyz = [d + (e and axis_aligned) for d, e in zip(dxyz, exyz)] + dvc = arcdiv * 4 * sum(fxyz) + if subdiv == ALL: + dvc += sum(p1 * p2 for p1, p2 in permutations(fxyz, 2)) + elif subdiv == EDGES: + # (0, 0, 2, 4) * sum(dxyz) + (0, 0, 2, 6) + dvc += ec * ec // 2 * sum(dxyz) + ec * (ec - 1) if axis_aligned else 0 + else: + dvc = (arcdiv * 4) * ec + ec * (ec - 1) if axis_aligned else 0 + vert_count = int(6 * arcdiv*arcdiv + (0 if odd_aligned else 2) + dvc) + if not radius and not max(size) > 0: + vert_count = 1 + return arcdiv, lindiv, vert_count + + if not radius and not max(size) > 0: + return [(0,0,0)], [] + + # uv lookup table + uvlt = [] + v = vi + for j in range(1, steps + 1): + v2 = v*v + uvlt.append((v, v2, radius * sqrt(18. - 6. * v2) / 6.)) + v = vi + j * step_size # v += step_size # instead of accumulating errors + # clear precision errors / signs at axis + if abs(v) < 1e-10: + v = 0.0 + + # Round cube sides built left to right bottom up + # xp yp zp xd yd zd + sides = ((0, 2, 1, (-1, 1, 1)), # Y+ Front + (1, 2, 0, (-1, -1, 1)), # X- Left + (0, 2, 1, ( 1, -1, 1)), # Y- Back + (1, 2, 0, ( 1, 1, 1)), # X+ Right + (0, 1, 2, (-1, 1, -1)), # Z- Bottom + (0, 1, 2, (-1, -1, 1))) # Z+ Top + + # side vertex index table + svit = [[[] for i in range(steps)] for i in range(6)] + # Extend rows for extrusion + if ey: + yer = axis_aligned + (dxyz[1] if subdiv else 0) + svit[4].extend([[] for i in range(yer)]) + svit[5].extend([[] for i in range(yer)]) + if ez: + zer = axis_aligned + (dxyz[2] if subdiv else 0) + for side in range(4): + svit[side].extend([[] for i in range(zer)]) + ryi = rzi = 0 # row vertex indices + # Extend rows for odd_aligned + if odd_aligned: + for side in range(4): + svit[side].append([]) + + hemi = steps // 2 + + # Create vertices and svit without dups + vert = [0., 0., 0.] + verts = [] + + if arcdiv == 1 and not odd_aligned and subdiv == ALL: + # Special case: 3D Grid Cuboid + for side, (xp, yp, zp, dir) in enumerate(sides): + svitc = svit[side] + rows = len(svitc) + if rows < dxyz[yp] + 2: + svitc.extend([[] for i in range(dxyz[yp] + 2 - rows)]) + vert[zp] = (half_chord + exyz[zp]) * dir[zp] + print(dssxyz, half_chord, exyz, dir) + for j in range(dxyz[yp] + 2): + vert[yp] = (j * dssxyz[yp] - half_chord - exyz[yp]) * dir[yp] + for i in range(dxyz[xp] + 2): + vert[xp] = (i * dssxyz[xp] - half_chord - exyz[xp]) * dir[xp] + if (side == 5) or ((i < dxyz[xp] + 1 and j < dxyz[yp] + 1) and (side < 4 or (i and j))): + print(side, vert) + svitc[j].append(len(verts)) + verts.append(tuple(vert)) + else: + for j in range(steps): + v, v2, mv2 = uvlt[j] + tv2mh = 1./3. * v2 - 0.5 + hv2 = 0.5 * v2 + + if j == hemi: + # Jump over non-edge row vertex indices + if ey: + ryi += yer + if ez: + rzi += zer + + for i in range(steps): + u, u2, mu2 = uvlt[i] + x = u * mv2 + y = v * mu2 + z = radius * sqrt(u2 * tv2mh - hv2 + 1.) + + for side, (xp, yp, zp, dir) in enumerate(sides): + svitc = svit[side] + ri = rzi if side < 4 else ryi + + vert[xp] = x + vert[yp] = y + vert[zp] = z + exr = exyz[xp] + eyr = exyz[yp] + + if (side == 5) or (i < arcdiv and j < arcdiv and (side < 4 or (i and j or odd_aligned))): + vert[0] = (vert[0] + copysign(ex, vert[0])) * dir[0] + vert[1] = (vert[1] + copysign(ey, vert[1])) * dir[1] + vert[2] = (vert[2] + copysign(ez, vert[2])) * dir[2] + rv = tuple(vert) + + if exr and i == hemi: + rx = vert[xp] # save xp + vert[xp] = rxi = (-exr - half_chord) * dir[xp] + if axis_aligned: + svitc[ri].append(len(verts)) + verts.append(tuple(vert)) + if subdiv: + offsetx = dssxyz[xp] * dir[xp] + for k in range(dxyz[xp]): + vert[xp] += offsetx + svitc[ri].append(len(verts)) + verts.append(tuple(vert)) + if eyr and j == hemi and axis_aligned: + vert[xp] = rxi + vert[yp] = -eyr * dir[yp] + svitc[hemi].append(len(verts)) + verts.append(tuple(vert)) + if subdiv: + offsety = dssxyz[yp] * dir[yp] + ry = vert[yp] + for k in range(dxyz[yp]): + vert[yp] += offsety + svitc[hemi + axis_aligned + k].append(len(verts)) + verts.append(tuple(vert)) + vert[yp] = ry + for k in range(dxyz[xp]): + vert[xp] += offsetx + svitc[hemi].append(len(verts)) + verts.append(tuple(vert)) + if subdiv & ALL: + for l in range(dxyz[yp]): + vert[yp] += offsety + svitc[hemi + axis_aligned + l].append(len(verts)) + verts.append(tuple(vert)) + vert[yp] = ry + vert[xp] = rx # restore + + if eyr and j == hemi: + vert[yp] = (-eyr - half_chord) * dir[yp] + if axis_aligned: + svitc[hemi].append(len(verts)) + verts.append(tuple(vert)) + if subdiv: + offsety = dssxyz[yp] * dir[yp] + for k in range(dxyz[yp]): + vert[yp] += offsety + if exr and i == hemi and not axis_aligned and subdiv & ALL: + vert[xp] = rxi + for l in range(dxyz[xp]): + vert[xp] += offsetx + svitc[hemi + k].append(len(verts)) + verts.append(tuple(vert)) + vert[xp] = rx + svitc[hemi + axis_aligned + k].append(len(verts)) + verts.append(tuple(vert)) + + svitc[ri].append(len(verts)) + verts.append(rv) + ryi += 1 + rzi += 1 + + # Complete svit edges (shared vertices) + # Sides' right edge + for side, rows in enumerate(svit[:4]): + for j, row in enumerate(rows[:-1]): + svit[3 if not side else side - 1][j].append(row[0]) + # Sides' top edge + for j, row in enumerate(svit[5]): + if not j: + for col in row: + svit[0][-1].append(col) + if j == len(svit[5]) - 1: + for col in reversed(row): + svit[2][-1].append(col) + svit[3][-1].insert(0, row[0]) + svit[1][-1].append(row[-1]) + if odd_aligned: + for side in svit[:4]: + side[-1].append(-1) + # Bottom edges + if odd_aligned: + svit[4].insert(0, [-1] + svit[2][0][-2::-1] + [-1]) + for i, col in enumerate(svit[3][0][:-1]): + svit[4][i + 1].insert(0, col) + svit[4][i + 1].append(svit[1][0][-i - 2]) + svit[4].append([-1] + svit[0][0][:-1] + [-1]) + else: + svit[4][0].extend(svit[2][0][::-1]) + for i, col in enumerate(svit[3][0][1:-1]): + svit[4][i + 1].insert(0, col) + svit[4][i + 1].append(svit[1][0][-i - 2]) + svit[4][-1].extend(svit[0][0]) + + # Build faces + faces = [] + if not axis_aligned: + hemi -= 1 + for side, rows in enumerate(svit): + xp, yp = sides[side][:2] + oa4 = odd_aligned and side == 4 + if oa4: # special case + hemi += 1 + for j, row in enumerate(rows[:-1]): + tri = odd_aligned and (oa4 and not j or rows[j+1][-1] < 0) + for i, vi in enumerate(row[:-1]): + # odd_aligned triangle corners + if vi < 0: + if not j and not i: + faces.append((row[i+1], rows[j+1][i+1], rows[j+1][i])) + elif oa4 and not i and j == len(rows) - 2: + faces.append((vi, row[i+1], rows[j+1][i+1])) + elif tri and i == len(row) - 2: + if j: + faces.append((vi, row[i+1], rows[j+1][i])) + else: + if oa4 or arcdiv > 1: + faces.append((vi, rows[j+1][i+1], rows[j+1][i])) + else: + faces.append((vi, row[i+1], rows[j+1][i])) + # subdiv = EDGES (not ALL) + elif subdiv and len(rows[j + 1]) < len(row) and (i >= hemi): + if (i == hemi): + faces.append((vi, row[i+1+dxyz[xp]], rows[j+1+dxyz[yp]][i+1+dxyz[xp]], rows[j+1+dxyz[yp]][i])) + elif i > hemi + dxyz[xp]: + faces.append((vi, row[i+1], rows[j+1][i+1-dxyz[xp]], rows[j+1][i-dxyz[xp]])) + elif subdiv and len(rows[j + 1]) > len(row) and (i >= hemi): + if (i > hemi): + faces.append((vi, row[i+1], rows[j+1][i+1+dxyz[xp]], rows[j+1][i+dxyz[xp]])) + elif subdiv and len(row) < len(rows[0]) and i == hemi: + pass + else: + # Most faces... + faces.append((vi, row[i+1], rows[j+1][i+1], rows[j+1][i])) + if oa4: + hemi -= 1 + + return verts, faces + +from bpy.props import BoolProperty, EnumProperty, FloatProperty, FloatVectorProperty, IntProperty + +class AddRoundCube(bpy.types.Operator): + """Add Round Cube Primitive""" + bl_idname = 'mesh.primitive_round_cube_add' + bl_label = 'Add Round Cube' + bl_description = 'Add mesh primitives: Quadsphere, Capsule, Rounded Cuboid, 3D Grid' + bl_options = {'REGISTER', 'UNDO', 'PRESET'} + + sanity_check_verts = 200000 + + radius = FloatProperty( + name = 'Radius', + description = 'Radius of vertices for sphere, capsule or cuboid bevel', + default = 1.0, min = 0.0, soft_min=0.01, step=10 + ) + + size = FloatVectorProperty( + name = 'Size', + description = 'Size', + subtype = 'XYZ', + ) + + arc_div = IntProperty( + name = 'Arc Divisions', + description = 'Arc curve divisions, per quadrant; 0 = derive from Linear', + default = 4, min = 0 + ) + + lin_div = FloatProperty( + name = 'Linear Divisions', + description = 'Linear unit divisions (Edges/Faces); 0 = derive from Arc', + default = 0.0, min = 0.0, step=100, precision=1 + ) + + div_type = EnumProperty( + name = 'Type', + description = 'Division type', + items = ( + ('CORNERS', 'Corners', 'Sphere / Corners'), + ('EDGES', 'Edges', 'Sphere / Corners and extruded edges (size)'), + ('ALL', 'All', 'Sphere / Corners, extruded edges and faces (size)')), + default = 'CORNERS', + ) + + odd_axis_align = BoolProperty( + name='Odd Axis Align', + description = 'Align odd arc divisions with axes (Note: triangle corners!)', + ) + + no_limit = BoolProperty( + name='No Limit', + description = 'Do not limit to '+str(sanity_check_verts)+' vertices (sanity check)', + ) + + preset = EnumProperty( + name = 'Presets', + items = ( + ('CUSTOM', 'Custom', 'Round Cube'), + ('SPHERE', 'Sphere', 'Quadsphere'), + ('CAPSULE', 'Capsule', 'Capsule'), + ('CUBOID', 'Cube', 'Rounded Cuboid'), + ('3DGRID', 'Grid', '3D Grid Cube')), + default = 'CUSTOM', options={'HIDDEN'} + ) + + def execute(self, context): + if self.preset == 'SPHERE': + self.radius = 1.0 + self.size = (0.,0.,0.) + self.arc_div = max(self.arc_div, 4) + self.lin_div = 0. + self.div_type = 'CORNERS' + elif self.preset == 'CAPSULE': + self.radius = 0.5 + self.size = (0.,0.,3.) + self.arc_div = max(self.arc_div, 4) + self.lin_div = 0. + self.div_type = 'CORNERS' + elif self.preset == 'CUBOID': + self.radius = 0.25 + self.size = (2.,2.,2.) + self.arc_div = max(self.arc_div, 4) + self.lin_div = 0. + self.div_type = 'CORNERS' + elif self.preset == '3DGRID': + self.radius = 1.0 + self.arc_div = 1 + self.lin_div = max(self.lin_div, 5.) + self.div_type = 'ALL' + self.size = (2.,2.,2.) + self.odd_axis_align = False + self.preset = 'CUSTOM' + + if self.arc_div <=0 and self.lin_div <= 0: + self.report({'ERROR'}, 'Either Arc Divisions or Linear Divisions must be greater than zero!') + return {'CANCELLED'} + + if not self.no_limit: + arcdiv, lindiv, vert_count = round_cube(self.radius, self.arc_div, self.lin_div, self.size, self.div_type, self.odd_axis_align, True) + if vert_count > self.sanity_check_verts: + self.report({'ERROR'}, 'More than '+str(self.sanity_check_verts)+' vertices! Check "No Limit" to proceed') + return {'CANCELLED'} + + verts, faces = round_cube(self.radius, self.arc_div, self.lin_div, self.size, self.div_type, self.odd_axis_align) + + mesh = bpy.data.meshes.new('Roundcube') + mesh.from_pydata(verts,[],faces) + object_utils.object_data_add(context, mesh, operator=None) + + return {'FINISHED'} + + def draw(self, context): + + arcdiv, lindiv, vert_count = round_cube(self.radius, self.arc_div, self.lin_div, self.size, self.div_type, self.odd_axis_align, True) + + layout = self.layout + + layout.prop(self, 'radius') + row = layout.row() + row.column().prop(self, 'size', expand=True) + + box = layout.box() + row = box.row() + row.alignment = 'CENTER' + row.scale_y = 0.1 + row.label('Divisions') + row = box.row()# align=True) + col = row.column() + col.alignment = 'RIGHT' + col.label('Arc:') + col.prop(self, 'arc_div', text="") + col.label('[ {} ]'.format(arcdiv)) + col = row.column() + col.alignment = 'RIGHT' + col.label('Linear:') + col.prop(self, 'lin_div', text="") + col.label('[ {:.3g} ]'.format(lindiv)) + box.row().prop(self, 'div_type') + row = box.row() + row.active = arcdiv % 2 + row.prop(self, 'odd_axis_align') + + row = layout.row() + row.alert = vert_count > self.sanity_check_verts + row.prop(self, 'no_limit', text='No limit ({})'.format(vert_count)) + +class INFO_MT_mesh_round_cube_add(bpy.types.Menu): + bl_idname = 'INFO_MT_mesh_round_cube_add' + bl_label = 'Round Cube' + def draw(self, context): + layout = self.layout + layout.operator_context = 'INVOKE_REGION_WIN' + layout.operator(AddRoundCube.bl_idname, text = 'Custom', icon='MOD_SUBSURF') + layout.operator(AddRoundCube.bl_idname, text = 'Sphere', icon='META_BALL').preset = 'SPHERE' + layout.operator(AddRoundCube.bl_idname, text = 'Capsule', icon='META_ELLIPSOID').preset = 'CAPSULE' + layout.operator(AddRoundCube.bl_idname, text = 'Cube', icon='META_CUBE').preset = 'CUBOID' + layout.operator(AddRoundCube.bl_idname, text = 'Grid', icon='META_CUBE').preset = '3DGRID' + diff --git a/add_mesh_extra_objects/add_mesh_solid.py b/add_mesh_extra_objects/add_mesh_solid.py index 20584ea7..d2243fd3 100644 --- a/add_mesh_extra_objects/add_mesh_solid.py +++ b/add_mesh_extra_objects/add_mesh_solid.py @@ -1,26 +1,5 @@ -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ***** END GPL LICENCE BLOCK ***** -''' - "name": "Regular Solids", - "author": "DreamPainter", - "version": (2, 0), -''' +# GPL # "author": "DreamPainter" + import bpy from bpy.props import FloatProperty,EnumProperty,BoolProperty from math import sqrt diff --git a/add_mesh_extra_objects/add_mesh_star.py b/add_mesh_extra_objects/add_mesh_star.py new file mode 100644 index 00000000..9bdd0b83 --- /dev/null +++ b/add_mesh_extra_objects/add_mesh_star.py @@ -0,0 +1,174 @@ +# GPL Original by Fourmadmen + +import bpy +from mathutils import * +from math import * +from bpy.props import * + +# Create a new mesh (object) from verts/edges/faces. +# verts/edges/faces ... List of vertices/edges/faces for the +# new mesh (as used in from_pydata). +# name ... Name of the new mesh (& object). +def create_mesh_object(context, verts, edges, faces, name): + + # Create new mesh + mesh = bpy.data.meshes.new(name) + + # Make a mesh from a list of verts/edges/faces. + mesh.from_pydata(verts, edges, faces) + + # Update mesh geometry after adding stuff. + mesh.update() + + from bpy_extras import object_utils + return object_utils.object_data_add(context, mesh, operator=None) + +# A very simple "bridge" tool. + +def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False): + faces = [] + + if not vertIdx1 or not vertIdx2: + return None + + if len(vertIdx1) < 2 and len(vertIdx2) < 2: + return None + + fan = False + if (len(vertIdx1) != len(vertIdx2)): + if (len(vertIdx1) == 1 and len(vertIdx2) > 1): + fan = True + else: + return None + + total = len(vertIdx2) + + if closed: + # Bridge the start with the end. + if flipped: + face = [ + vertIdx1[0], + vertIdx2[0], + vertIdx2[total - 1]] + if not fan: + face.append(vertIdx1[total - 1]) + faces.append(face) + + else: + face = [vertIdx2[0], vertIdx1[0]] + if not fan: + face.append(vertIdx1[total - 1]) + face.append(vertIdx2[total - 1]) + faces.append(face) + + # Bridge the rest of the faces. + for num in range(total - 1): + if flipped: + if fan: + face = [vertIdx2[num], vertIdx1[0], vertIdx2[num + 1]] + else: + face = [vertIdx2[num], vertIdx1[num], + vertIdx1[num + 1], vertIdx2[num + 1]] + faces.append(face) + else: + if fan: + face = [vertIdx1[0], vertIdx2[num], vertIdx2[num + 1]] + else: + face = [vertIdx1[num], vertIdx2[num], + vertIdx2[num + 1], vertIdx1[num + 1]] + faces.append(face) + + return faces + + +# @todo Clean up vertex&face creation process a bit. + +def add_star(points, outer_radius, inner_radius, height): + PI_2 = pi * 2 + z_axis = (0, 0, 1) + + verts = [] + faces = [] + + segments = points * 2 + + half_height = height / 2.0 + + vert_idx_top = len(verts) + verts.append(Vector((0.0, 0.0, half_height))) + + vert_idx_bottom = len(verts) + verts.append(Vector((0.0, 0.0, -half_height))) + + edgeloop_top = [] + edgeloop_bottom = [] + + for index in range(segments): + quat = Quaternion(z_axis, (index / segments) * PI_2) + + if index % 2: + # Uneven + radius = outer_radius + else: + # Even + radius = inner_radius + + edgeloop_top.append(len(verts)) + vec = quat * Vector((radius, 0, half_height)) + verts.append(vec) + + edgeloop_bottom.append(len(verts)) + vec = quat * Vector((radius, 0, -half_height)) + verts.append(vec) + + + + faces_top = createFaces([vert_idx_top], edgeloop_top, closed=True) + faces_outside = createFaces(edgeloop_top, edgeloop_bottom, closed=True) + faces_bottom = createFaces([vert_idx_bottom], edgeloop_bottom, + flipped=True, closed=True) + + faces.extend(faces_top) + faces.extend(faces_outside) + faces.extend(faces_bottom) + + return verts, faces + +class AddStar(bpy.types.Operator): + """Add a star mesh""" + bl_idname = "mesh.primitive_star_add" + bl_label = "Simple Star" + bl_options = {'REGISTER', 'UNDO', 'PRESET'} + + points = IntProperty(name="Points", + description="Number of points for the star", + min=2, + max=256, + default=5) + outer_radius = FloatProperty(name="Outer Radius", + description="Outer radius of the star", + min=0.01, + max=9999.0, + default=1.0) + innter_radius = FloatProperty(name="Inner Radius", + description="Inner radius of the star", + min=0.01, + max=9999.0, + default=0.5) + height = FloatProperty(name="Height", + description="Height of the star", + min=0.01, + max=9999.0, + default=0.5) + + def execute(self, context): + + verts, faces = add_star( + self.points, + self.outer_radius, + self.innter_radius, + self.height) + + obj = create_mesh_object(context, verts, [], faces, "Star") + + return {'FINISHED'} diff --git a/add_mesh_extra_objects/add_mesh_supertoroid.py b/add_mesh_extra_objects/add_mesh_supertoroid.py index c9fd8f99..895281e1 100644 --- a/add_mesh_extra_objects/add_mesh_supertoroid.py +++ b/add_mesh_extra_objects/add_mesh_supertoroid.py @@ -1,8 +1,5 @@ -''' - "name": "Add Mesh: SuperToroid", - "author": "DreamPainter", - "version": (1, 0, 0), -''' +# GPL # "author": "DreamPainter" + import bpy from bpy.props import FloatProperty,BoolProperty,IntProperty from math import pi, cos, sin @@ -28,18 +25,7 @@ def create_mesh_object(context, verts, edges, faces, name): return object_utils.object_data_add(context, mesh, operator=None) # A very simple "bridge" tool. -# Connects two equally long vertex rows with faces. -# Returns a list of the new faces (list of lists) -# -# vertIdx1 ... First vertex list (list of vertex indices). -# vertIdx2 ... Second vertex list (list of vertex indices). -# closed ... Creates a loop (first & last are closed). -# flipped ... Invert the normal of the face(s). -# -# Note: You can set vertIdx1 to a single vertex index to create -# a fan/star of faces. -# Note: If both vertex idx list are the same length they have -# to have at least 2 vertices. + def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False): faces = [] diff --git a/add_mesh_extra_objects/add_mesh_teapot.py b/add_mesh_extra_objects/add_mesh_teapot.py index d7cdfcd5..01b16a38 100644 --- a/add_mesh_extra_objects/add_mesh_teapot.py +++ b/add_mesh_extra_objects/add_mesh_teapot.py @@ -1,30 +1,4 @@ -# +---------------------------------------------------------+ -# | Copyright (c) 2005-2010 Anthony D'Agostino | -# | http://home.comcast.net/~chronosphere | -# | scorpius@netzero.com | -# | February 12, 2005 | -# | Newell Teapot Generator | -# | Adds the famous missing primitive to Blender | -# +---------------------------------------------------------+ - -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# ***** END GPL LICENCE BLOCK ***** -# "version": (1, 0, 0) +# GPL # Author, Anthony D'Agostino import bpy from bpy.props import IntProperty diff --git a/add_mesh_extra_objects/add_mesh_torusknot.py b/add_mesh_extra_objects/add_mesh_torusknot.py index 3803ba62..24bb9b4e 100644 --- a/add_mesh_extra_objects/add_mesh_torusknot.py +++ b/add_mesh_extra_objects/add_mesh_torusknot.py @@ -1,30 +1,5 @@ -# +---------------------------------------------------------+ -# | Copyright (c) 2005-2010 Anthony D'Agostino | -# | http://home.comcast.net/~chronosphere | -# | scorpius@netzero.com | -# | February 12, 2005 | -# | Torus Knot Generator | -# | Adds the famous missing primitive to Blender | -# +---------------------------------------------------------+ +# GPL # Author, Anthony D'Agostino -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# ***** END GPL LICENCE BLOCK ***** -# "version": (1, 0, 0) import bpy, mathutils, math def create_mesh_object(context, verts, edges, faces, name): diff --git a/add_mesh_extra_objects/add_mesh_twisted_torus.py b/add_mesh_extra_objects/add_mesh_twisted_torus.py index 2392a293..485030cc 100644 --- a/add_mesh_extra_objects/add_mesh_twisted_torus.py +++ b/add_mesh_extra_objects/add_mesh_twisted_torus.py @@ -1,34 +1,5 @@ -# add_mesh_twisted_torus.py Copyright (C) 2009-2010, Paulo Gomes -# tuga3d {at} gmail {dot} com -# add twisted torus to the blender 2.50 add->mesh menu -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ***** END GPL LICENCE BLOCK ***** -#twisted torus by Paulo_Gomes -# "version": (0, 11, 1) - -""" -Usage: - -* Launch from Add Mesh menu - -* Modify parameters as desired or keep defaults -""" +# GPL # by Paulo_Gomes + import bpy from bpy.props import * @@ -54,18 +25,6 @@ def create_mesh_object(context, verts, edges, faces, name): return object_utils.object_data_add(context, mesh, operator=None) # A very simple "bridge" tool. -# Connects two equally long vertex rows with faces. -# Returns a list of the new faces (list of lists) -# -# vertIdx1 ... First vertex list (list of vertex indices). -# vertIdx2 ... Second vertex list (list of vertex indices). -# closed ... Creates a loop (first & last are closed). -# flipped ... Invert the normal of the face(s). -# -# Note: You can set vertIdx1 to a single vertex index to create -# a fan/star of faces. -# Note: If both vertex idx list are the same length they have -# to have at least 2 vertices. def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False): faces = [] diff --git a/add_mesh_extra_objects/add_mesh_vertex.py b/add_mesh_extra_objects/add_mesh_vertex.py new file mode 100644 index 00000000..10c86657 --- /dev/null +++ b/add_mesh_extra_objects/add_mesh_vertex.py @@ -0,0 +1,142 @@ +# GPL # Originals by meta-androcto, Pablo Vazquez, Liero, Richard Wilks + +import bpy +import bmesh +from bpy.props import StringProperty, FloatProperty, BoolProperty, FloatVectorProperty + + # add the mesh as an object into the scene with this utility module +from bpy_extras import object_utils + + + +def object_origin(width, height, depth): + """ + This function takes inputs and returns vertex and face arrays. + no actual mesh data creation is done here. + """ + + verts = [(+0.0, +0.0, +0.0) + ] + + faces = [] + + # apply size + for i, v in enumerate(verts): + verts[i] = v[0] * width, v[1] * depth, v[2] * height + + return verts, faces + +class AddVert(bpy.types.Operator): + '''Add a Single Vertice to Edit Mode''' + bl_idname = "mesh.primitive_vert_add" + bl_label = "Single Vert" + bl_options = {'REGISTER', 'UNDO'} + + def execute(self, context): + mesh = bpy.data.meshes.new("Vert") + mesh.vertices.add(1) + + from bpy_extras import object_utils + object_utils.object_data_add(context, mesh, operator=None) + bpy.ops.object.mode_set(mode = 'EDIT') + + return {'FINISHED'} + +class AddEmptyVert(bpy.types.Operator): + '''Add an Object Origin to Edit Mode''' + bl_idname = "mesh.primitive_emptyvert_add" + bl_label = "Empty Object Origin" + bl_options = {'REGISTER', 'UNDO'} + + def execute(self, context): + mesh = bpy.data.meshes.new("Vert") + mesh.vertices.add(1) + + from bpy_extras import object_utils + object_utils.object_data_add(context, mesh, operator=None) + bpy.ops.object.mode_set(mode = 'EDIT') + bpy.ops.mesh.delete(type='VERT') + + return {'FINISHED'} + +def Add_Symmetrical_Empty(): + + bpy.ops.mesh.primitive_plane_add(enter_editmode = True) + + sempty = bpy.context.object + sempty.name = "SymmEmpty" + + # check if we have a mirror modifier, otherwise add + if (sempty.modifiers and sempty.modifiers['Mirror']): + pass + else: + bpy.ops.object.modifier_add(type ='MIRROR') + + # Delete all! + bpy.ops.mesh.select_all(action='TOGGLE') + bpy.ops.mesh.select_all(action='TOGGLE') + bpy.ops.mesh.delete(type ='VERT') + +def Add_Symmetrical_Vert(): + + bpy.ops.mesh.primitive_plane_add(enter_editmode = True) + + sempty = bpy.context.object + sempty.name = "SymmVert" + + # check if we have a mirror modifier, otherwise add + if (sempty.modifiers and sempty.modifiers['Mirror']): + pass + else: + bpy.ops.object.modifier_add(type ='MIRROR') + + # Delete all! + bpy.ops.mesh.select_all(action='TOGGLE') + bpy.ops.mesh.select_all(action='TOGGLE') + bpy.ops.mesh.merge(type='CENTER') + +class AddSymmetricalEmpty(bpy.types.Operator): + + bl_idname = "mesh.primitive_symmetrical_empty_add" + bl_label = "Add Symmetrical Object Origin" + bl_description = "Object Origin with a Mirror Modifier for symmetrical modeling" + bl_options = {'REGISTER', 'UNDO'} + + def draw(self, context): + layout = self.layout + mirror = bpy.context.object.modifiers['Mirror'] + + layout.prop(mirror,'use_clip', text="Use Clipping") + + layout.label("Mirror Axis") + row = layout.row(align=True) + row.prop(mirror, "use_x") + row.prop(mirror, "use_y") + row.prop(mirror, "use_z") + + def execute(self, context): + Add_Symmetrical_Empty() + return {'FINISHED'} + +class AddSymmetricalVert(bpy.types.Operator): + + bl_idname = "mesh.primitive_symmetrical_vert_add" + bl_label = "Add Symmetrical Origin & Vert" + bl_description = "Object Origin with a Mirror Modifier for symmetrical modeling" + bl_options = {'REGISTER', 'UNDO'} + + def draw(self, context): + layout = self.layout + mirror = bpy.context.object.modifiers['Mirror'] + + layout.prop(mirror,'use_clip', text="Use Clipping") + + layout.label("Mirror Axis") + row = layout.row(align=True) + row.prop(mirror, "use_x") + row.prop(mirror, "use_y") + row.prop(mirror, "use_z") + + def execute(self, context): + Add_Symmetrical_Vert() + return {'FINISHED'} -- cgit v1.2.3