Add mesh extra objects: Update to version 0.3.1

General Pep8 cleanup
Removed unused variables and imports
Removed a panel from add_empty_as_parent
Standardized the property definitions
across all the scripts
Moved scene props from third_domes_panel_271
to init for proper removal
Added a Enum prop for mesh type in teapot
Fixed a small issue with Geodesic domes self.reports
(problem with value fields message spam)
Fixed props names in Geodesic domes
Consistent tooltips
Reorganized menus:
Mechanical Menu including Pipe joints, Mesh gear
Added separators
This commit is contained in:
Vuk Gardašević 2016-12-30 20:33:05 +01:00
parent c95e86bcef
commit c86080a455
27 changed files with 4950 additions and 3855 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -16,14 +16,15 @@
#
# ##### END GPL LICENSE BLOCK #####
# Contributed to by:
# Pontiac, Fourmadmen, varkenvarken, tuga3d, meta-androcto, metalliandy, dreampainter, cotejrp1 #
# liero, Kayo Phoenix, sugiany, dommetysk, Phymec, Anthony D'Agostino, Pablo Vazquez, Richard Wilks #
# Pontiac, Fourmadmen, varkenvarken, tuga3d, meta-androcto, metalliandy #
# dreampainter, cotejrp1, liero, Kayo Phoenix, sugiany, dommetysk #
# Phymec, Anthony D'Agostino, Pablo Vazquez, Richard Wilks, lijenstina #
# xyz presets by elfnor
bl_info = {
"name": "Extra Objects",
"author": "Multiple Authors",
"version": (0, 3, 0),
"version": (0, 3, 1),
"blender": (2, 74, 5),
"location": "View3D > Add > Mesh",
"description": "Add extra mesh object types",
@ -87,15 +88,17 @@ else:
from . import Blocks
import bpy
from bpy.types import Menu
from bpy.props import (
BoolProperty,
IntProperty,
FloatProperty,
StringProperty,
)
class INFO_MT_mesh_vert_add(bpy.types.Menu):
# Define the "Pipe Joints" menu
class INFO_MT_mesh_vert_add(Menu):
# Define the "Single Vert" menu
bl_idname = "INFO_MT_mesh_vert_add"
bl_label = "Single Vert"
@ -103,7 +106,8 @@ class INFO_MT_mesh_vert_add(bpy.types.Menu):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
layout.operator("mesh.primitive_vert_add",
text="Add Single Vert ")
text="Add Single Vert")
layout.separator()
layout.operator("mesh.primitive_emptyvert_add",
text="Object Origin Only")
layout.operator("mesh.primitive_symmetrical_vert_add",
@ -112,7 +116,7 @@ class INFO_MT_mesh_vert_add(bpy.types.Menu):
text="Object Origin Mirrored")
class INFO_MT_mesh_gears_add(bpy.types.Menu):
class INFO_MT_mesh_gears_add(Menu):
# Define the "Gears" menu
bl_idname = "INFO_MT_mesh_gears_add"
bl_label = "Gears"
@ -126,8 +130,8 @@ class INFO_MT_mesh_gears_add(bpy.types.Menu):
text="Worm")
class INFO_MT_mesh_diamonds_add(bpy.types.Menu):
# Define the "Gears" menu
class INFO_MT_mesh_diamonds_add(Menu):
# Define the "Diamonds" menu
bl_idname = "INFO_MT_mesh_diamonds_add"
bl_label = "Diamonds"
@ -142,7 +146,7 @@ class INFO_MT_mesh_diamonds_add(bpy.types.Menu):
text="Gem")
class INFO_MT_mesh_math_add(bpy.types.Menu):
class INFO_MT_mesh_math_add(Menu):
# Define the "Math Function" menu
bl_idname = "INFO_MT_mesh_math_add"
bl_label = "Math Functions"
@ -157,19 +161,36 @@ class INFO_MT_mesh_math_add(bpy.types.Menu):
self.layout.operator("mesh.primitive_solid_add", text="Regular Solid")
class INFO_MT_mesh_extras_add(bpy.types.Menu):
# Define the "Simple Objects" menu
class INFO_MT_mesh_mech(Menu):
# Define the "Math Function" menu
bl_idname = "INFO_MT_mesh_mech_add"
bl_label = "Mechanical"
def draw(self, context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
layout.menu("INFO_MT_mesh_pipe_joints_add",
text="Pipe Joints", icon="SNAP_PEEL_OBJECT")
layout.menu("INFO_MT_mesh_gears_add",
text="Gears", icon="SCRIPTWIN")
class INFO_MT_mesh_extras_add(Menu):
# Define the "Extra Objects" menu
bl_idname = "INFO_MT_mesh_extras_add"
bl_label = "Extras"
def draw(self, context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
layout.menu("INFO_MT_mesh_diamonds_add", text="Diamonds", icon="PMARKER_SEL")
layout.menu("INFO_MT_mesh_diamonds_add", text="Diamonds",
icon="PMARKER_SEL")
layout.separator()
layout.operator("mesh.add_beam",
text="Beam Builder")
layout.operator("mesh.wall_add",
text="Wall Factory")
layout.separator()
layout.operator("mesh.primitive_star_add",
text="Simple Star")
layout.operator("mesh.primitive_steppyramid_add",
@ -182,8 +203,8 @@ class INFO_MT_mesh_extras_add(bpy.types.Menu):
text="Menger Sponge")
class INFO_MT_mesh_torus_add(bpy.types.Menu):
# Define the "Simple Objects" menu
class INFO_MT_mesh_torus_add(Menu):
# Define the "Torus Objects" menu
bl_idname = "INFO_MT_mesh_torus_add"
bl_label = "Torus Objects"
@ -198,7 +219,7 @@ class INFO_MT_mesh_torus_add(bpy.types.Menu):
text="Torus Knot")
class INFO_MT_mesh_pipe_joints_add(bpy.types.Menu):
class INFO_MT_mesh_pipe_joints_add(Menu):
# Define the "Pipe Joints" menu
bl_idname = "INFO_MT_mesh_pipe_joints_add"
bl_label = "Pipe Joints"
@ -219,9 +240,7 @@ class INFO_MT_mesh_pipe_joints_add(bpy.types.Menu):
class discombobulator_scene_props(bpy.types.PropertyGroup):
DISC_doodads = []
# Protusions Buttons:
repeatprot = IntProperty(
name="Repeat protusions",
@ -250,7 +269,6 @@ class discombobulator_scene_props(bpy.types.PropertyGroup):
name="4",
default=True
)
polygonschangedpercent = FloatProperty(
name="Polygon %",
description="Percentage of changed polygons",
@ -324,19 +342,29 @@ class discombobulator_scene_props(bpy.types.PropertyGroup):
def menu_func(self, context):
lay_out = self.layout
lay_out.operator_context = 'INVOKE_REGION_WIN'
lay_out.separator()
lay_out.menu("INFO_MT_mesh_vert_add", text="Single Vert", icon="LAYER_ACTIVE")
lay_out.operator("mesh.primitive_round_cube_add", text="Round Cube", icon="MOD_SUBSURF")
lay_out.menu("INFO_MT_mesh_math_add", text="Math Function", icon="PACKAGE")
lay_out.operator("mesh.generate_geodesic_dome", text="Geodesic Dome", icon="MESH_ICOSPHERE")
lay_out.operator("discombobulate.ops", text="Discombobulator", icon="RETOPO")
lay_out.menu("INFO_MT_mesh_pipe_joints_add", text="Pipe Joints", icon="SNAP_PEEL_OBJECT")
lay_out.menu("INFO_MT_mesh_gears_add", text="Gears", icon="SCRIPTWIN")
lay_out.menu("INFO_MT_mesh_torus_add", text="Torus Objects", icon="MESH_TORUS")
lay_out.menu("INFO_MT_mesh_extras_add", text="Extras", icon="MESH_DATA")
lay_out.menu("INFO_MT_mesh_vert_add",
text="Single Vert", icon="LAYER_ACTIVE")
lay_out.operator("mesh.primitive_round_cube_add",
text="Round Cube", icon="MOD_SUBSURF")
lay_out.menu("INFO_MT_mesh_math_add",
text="Math Function", icon="PACKAGE")
lay_out.menu("INFO_MT_mesh_mech_add",
text="Mechanical", icon="SCRIPTWIN")
lay_out.menu("INFO_MT_mesh_torus_add",
text="Torus Objects", icon="MESH_TORUS")
lay_out.separator()
lay_out.operator("object.parent_to_empty", text="Parent To Empty", icon="LINK_AREA")
lay_out.operator("mesh.generate_geodesic_dome",
text="Geodesic Dome", icon="MESH_ICOSPHERE")
lay_out.operator("discombobulate.ops",
text="Discombobulator", icon="RETOPO")
lay_out.separator()
lay_out.menu("INFO_MT_mesh_extras_add",
text="Extras", icon="MESH_DATA")
lay_out.separator()
lay_out.operator("object.parent_to_empty",
text="Parent To Empty", icon="LINK_AREA")
def register():
@ -346,6 +374,21 @@ def register():
bpy.types.Scene.discomb = bpy.props.PointerProperty(
type=discombobulator_scene_props
)
# Error messages for Geodesic Domes
bpy.types.Scene.error_message = StringProperty(
name="actual error",
default=""
)
bpy.types.Scene.geodesic_not_yet_called = BoolProperty(
name="geodesic_not_called",
default=True
)
bpy.types.Scene.gd_help_text_width = IntProperty(
name="Text Width",
description="The width above which the text wraps",
default=60,
max=180, min=20
)
# Add "Extras" menu to the "Add Mesh" menu
bpy.types.INFO_MT_mesh_add.append(menu_func)
@ -356,6 +399,9 @@ def unregister():
bpy.types.INFO_MT_mesh_add.remove(menu_func)
del bpy.types.Scene.discomb
del bpy.types.Scene.error_message
del bpy.types.Scene.geodesic_not_yet_called
del bpy.types.Scene.gd_help_text_width
bpy.utils.unregister_module(__name__)

View File

@ -1,26 +1,49 @@
# GPL # Original Author Liero #
import bpy
from bpy.props import StringProperty, BoolProperty, EnumProperty
from bpy.types import Operator
from bpy.props import (
StringProperty,
BoolProperty,
EnumProperty,
)
def centro(sel):
x = sum([obj.location[0] for obj in sel])/len(sel)
y = sum([obj.location[1] for obj in sel])/len(sel)
z = sum([obj.location[2] for obj in sel])/len(sel)
return (x,y,z)
x = sum([obj.location[0] for obj in sel]) / len(sel)
y = sum([obj.location[1] for obj in sel]) / len(sel)
z = sum([obj.location[2] for obj in sel]) / len(sel)
return (x, y, z)
class P2E(bpy.types.Operator):
bl_idname = 'object.parent_to_empty'
bl_label = 'Parent to Empty'
bl_description = 'Parent selected objects to a new Empty'
bl_options = {'REGISTER', 'UNDO'}
class P2E(Operator):
bl_idname = "object.parent_to_empty"
bl_label = "Parent 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 add objects to a group')
locat = bpy.props.EnumProperty(name='', items=[('CURSOR','Cursor','Cursor'),('ACTIVE','Active','Active'),
('CENTER','Center','Selection Center')],description='Empty location', default='CENTER')
renom = bpy.props.BoolProperty(name='Add Prefix', default=False, description='Add prefix to objects name')
nombre = StringProperty(
name="",
default='OBJECTS',
description='Give the empty / group a name'
)
grupo = BoolProperty(
name="Create Group",
default=False,
description="Also add objects to a group"
)
locat = EnumProperty(
name='',
items=[('CURSOR', 'Cursor', 'Cursor'), ('ACTIVE', 'Active', 'Active'),
('CENTER', 'Center', 'Selection Center')],
description='Empty location',
default='CENTER'
)
renom = BoolProperty(
name="Add Prefix",
default=False,
description="Add prefix to objects name"
)
@classmethod
def poll(cls, context):
@ -29,34 +52,38 @@ class P2E(bpy.types.Operator):
def draw(self, context):
layout = self.layout
layout.prop(self,'nombre')
layout.prop(self, "nombre")
column = layout.column(align=True)
column.prop(self,'locat')
column.prop(self,'grupo')
column.prop(self,'renom')
column.prop(self, "locat")
column.prop(self, "grupo")
column.prop(self, "renom")
def execute(self, context):
objs = context.selected_objects
act = context.object
sce = context.scene
try: bpy.ops.object.mode_set()
except: pass
try:
bpy.ops.object.mode_set()
except:
pass
if self.locat == 'CURSOR':
loc = sce.cursor_location
elif self.locat == 'ACTIVE':
loc = act.location
else:
loc = centro(objs)
bpy.ops.object.add(type='EMPTY',location=loc)
loc = centro(objs)
bpy.ops.object.add(type='EMPTY', location=loc)
context.object.name = self.nombre
context.object.show_name = True
context.object.show_x_ray = True
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:
@ -66,50 +93,37 @@ class P2E(bpy.types.Operator):
o.select = False
for o in objs:
if self.renom:
o.name = self.nombre+'_'+o.name
o.name = self.nombre + '_' + o.name
return {'FINISHED'}
class PreFix(bpy.types.Operator):
bl_idname = 'object.toggle_prefix'
bl_label = 'Toggle Sufix'
bl_description = 'Toggle parent name as sufix for c'
bl_options = {'REGISTER', 'UNDO'}
class PreFix(Operator):
bl_idname = "object.toggle_prefix"
bl_label = "Toggle Sufix"
bl_description = "Toggle parent name as sufix for c"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
act = bpy.context.object
act = context.object
return (act and act.type == 'EMPTY')
def execute(self, context):
act = bpy.context.object
act = context.object
objs = act.children
prefix = act.name+'_'
prefix = act.name + '_'
remove = False
for o in objs:
if o.name.startswith(prefix):
remove = True
break
if remove == True:
if remove is True:
for o in objs:
if o.name.startswith(prefix):
o.name = o.name.partition(prefix)[2]
else:
for o in objs:
o.name = prefix+o.name
o.name = prefix + o.name
return {'FINISHED'}
class PanelP2E(bpy.types.Panel):
bl_label = 'Parent to Empty'
bl_space_type = 'VIEW_3D'
bl_region_type = 'TOOLS'
bl_category = 'Relations'
def draw(self, context):
layout = self.layout
layout.operator('object.parent_to_empty')
layout.operator('object.toggle_prefix')

View File

@ -3,7 +3,14 @@
import bpy
from mathutils import *
from math import *
from bpy.props import *
from bpy.types import Operator
from bpy.props import (
StringProperty,
IntProperty,
FloatProperty,
BoolProperty,
)
# List of safe functions for eval()
safe_list = ['math', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'cosh',
@ -16,35 +23,36 @@ safe_dict = dict((k, globals().get(k, None)) for k in safe_list)
# Stores the values of a list of properties and the
# operator id in a property group ('recall_op') inside the object.
# operator id in a property group ('recall_op') inside the object
# Could (in theory) be used for non-objects.
# Note: Replaces any existing property group with the same name!
# ob ... Object to store the properties in.
# op ... The operator that should be used.
# ob ... Object to store the properties in
# op ... The operator that should be used
# op_args ... A dictionary with valid Blender
# properties (operator arguments/parameters).
# properties (operator arguments/parameters)
# Create a new mesh (object) from verts/edges/faces.
# 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).
# 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.
# Make a mesh from a list of verts/edges/faces
mesh.from_pydata(verts, edges, faces)
# Update mesh geometry after adding stuff.
# 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.
# A very simple "bridge" tool
def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False):
faces = []
@ -65,7 +73,7 @@ def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False):
total = len(vertIdx2)
if closed:
# Bridge the start with the end.
# Bridge the start with the end
if flipped:
face = [
vertIdx1[0],
@ -82,7 +90,7 @@ def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False):
face.append(vertIdx2[total - 1])
faces.append(face)
# Bridge the rest of the faces.
# Bridge the rest of the faces
for num in range(total - 1):
if flipped:
if fan:
@ -102,39 +110,47 @@ def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False):
return faces
class AddZFunctionSurface(bpy.types.Operator):
"""Add a surface defined defined by a function z=f(x,y)"""
class AddZFunctionSurface(Operator):
bl_idname = "mesh.primitive_z_function_surface"
bl_label = "Add Z Function Surface"
bl_description = "Add a surface defined defined by a function z=f(x,y)"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
equation = StringProperty(name="Z Equation",
description="Equation for z=f(x,y)",
default="1 - ( x**2 + y**2 )")
div_x = IntProperty(name="X Subdivisions",
description="Number of vertices in x direction",
default=16,
min=3,
max=256)
div_y = IntProperty(name="Y Subdivisions",
description="Number of vertices in y direction",
default=16,
min=3,
max=256)
size_x = FloatProperty(name="X Size",
description="Size of the x axis",
default=2.0,
min=0.01,
max=100.0,
unit="LENGTH")
size_y = FloatProperty(name="Y Size",
description="Size of the y axis",
default=2.0,
min=0.01,
max=100.0,
unit="LENGTH")
equation = StringProperty(
name="Z Equation",
description="Equation for z=f(x,y)",
default="1 - ( x**2 + y**2 )"
)
div_x = IntProperty(
name="X Subdivisions",
description="Number of vertices in x direction",
default=16,
min=3,
max=256
)
div_y = IntProperty(
name="Y Subdivisions",
description="Number of vertices in y direction",
default=16,
min=3,
max=256
)
size_x = FloatProperty(
name="X Size",
description="Size of the x axis",
default=2.0,
min=0.01,
max=100.0,
unit="LENGTH"
)
size_y = FloatProperty(
name="Y Size",
description="Size of the y axis",
default=2.0,
min=0.01,
max=100.0,
unit="LENGTH"
)
def execute(self, context):
equation = self.equation
@ -153,55 +169,67 @@ class AddZFunctionSurface(bpy.types.Operator):
edgeloop_prev = []
try:
expr_args = (
compile(equation, __file__, 'eval'),
{"__builtins__": None},
safe_dict)
except:
import traceback
self.report({'ERROR'}, "Error parsing expression: "
+ traceback.format_exc(limit=1))
if equation:
try:
expr_args = (
compile(equation, __file__, 'eval'),
{"__builtins__": None},
safe_dict)
except:
import traceback
# WARNING is used to prevent the constant pop-up spam
self.report({'WARNING'},
"Error parsing expression: {} "
"(Check the console for more info)".format(equation))
print("\n[Add Z Function Surface]:\n\n", traceback.format_exc(limit=1))
return {'CANCELLED'}
for row_x in range(div_x):
edgeloop_cur = []
x = start_x + row_x * delta_x
for row_y in range(div_y):
y = start_y + row_y * delta_y
z = 0.0
safe_dict['x'] = x
safe_dict['y'] = y
# Try to evaluate the equation.
try:
z = float(eval(*expr_args))
except:
import traceback
self.report({'WARNING'},
"Error evaluating expression: {} "
"(Check the console for more info)".format(equation))
print("\n[Add Z Function Surface]:\n\n", traceback.format_exc(limit=1))
return {'CANCELLED'}
edgeloop_cur.append(len(verts))
verts.append((x, y, z))
if len(edgeloop_prev) > 0:
faces_row = createFaces(edgeloop_prev, edgeloop_cur)
faces.extend(faces_row)
edgeloop_prev = edgeloop_cur
base = create_mesh_object(context, verts, [], faces, "Z Function")
else:
self.report({'WARNING'}, "Z Equation - No expression is given")
return {'CANCELLED'}
for row_x in range(div_x):
edgeloop_cur = []
x = start_x + row_x * delta_x
for row_y in range(div_y):
y = start_y + row_y * delta_y
z = 0.0
safe_dict['x'] = x
safe_dict['y'] = y
# Try to evaluate the equation.
try:
z = float(eval(*expr_args))
except:
import traceback
self.report({'ERROR'}, "Error evaluating expression: "
+ traceback.format_exc(limit=1))
return {'CANCELLED'}
edgeloop_cur.append(len(verts))
verts.append((x, y, z))
if len(edgeloop_prev) > 0:
faces_row = createFaces(edgeloop_prev, edgeloop_cur)
faces.extend(faces_row)
edgeloop_prev = edgeloop_cur
base = create_mesh_object(context, verts, [], faces, "Z Function")
return {'FINISHED'}
def xyz_function_surface_faces(self, x_eq, y_eq, z_eq,
range_u_min, range_u_max, range_u_step, wrap_u,
range_v_min, range_v_max, range_v_step, wrap_v,
a_eq, b_eq, c_eq, f_eq, g_eq, h_eq, n, close_v):
range_u_min, range_u_max, range_u_step, wrap_u,
range_v_min, range_v_max, range_v_step, wrap_v,
a_eq, b_eq, c_eq, f_eq, g_eq, h_eq, n, close_v):
verts = []
faces = []
@ -261,8 +289,9 @@ def xyz_function_surface_faces(self, x_eq, y_eq, z_eq,
safe_dict)
except:
import traceback
self.report({'ERROR'}, "Error parsing expression: "
+ traceback.format_exc(limit=1))
self.report({'WARNING'}, "Error parsing expression(s) - "
"Check the console for more info")
print("\n[Add X, Y, Z Function Surface]:\n\n", traceback.format_exc(limit=1))
return [], []
for vN in range(vRange):
@ -289,11 +318,11 @@ def xyz_function_surface_faces(self, x_eq, y_eq, z_eq,
float(eval(*expr_args_x)),
float(eval(*expr_args_y)),
float(eval(*expr_args_z))))
except:
import traceback
self.report({'ERROR'}, "Error evaluating expression: "
+ traceback.format_exc(limit=1))
self.report({'WARNING'}, "Error evaluating expression(s) - "
"Check the console for more info")
print("\n[Add X, Y, Z Function Surface]:\n\n", traceback.format_exc(limit=1))
return [], []
for vN in range(range_v_step):
@ -346,112 +375,131 @@ def xyz_function_surface_faces(self, x_eq, y_eq, z_eq,
# u_max = pi
# v_min = -pi/4,
# v max = 5*pi/2
class AddXYZFunctionSurface(bpy.types.Operator):
"""Add a surface defined defined by 3 functions:""" \
""" x=F1(u,v), y=F2(u,v) and z=F3(u,v)"""
class AddXYZFunctionSurface(Operator):
bl_idname = "mesh.primitive_xyz_function_surface"
bl_label = "Add X,Y,Z Function Surface"
bl_label = "Add X, Y, Z Function Surface"
bl_description = ("Add a surface defined defined by 3 functions:\n"
"x=F1(u,v), y=F2(u,v) and z=F3(u,v)")
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
x_eq = StringProperty(name="X equation",
description="Equation for x=F(u,v). " \
"Also available: n, a, b, c, f, g, h",
default="cos(v)*(1+cos(u))*sin(v/8)")
y_eq = StringProperty(name="Y equation",
description="Equation for y=F(u,v). " \
"Also available: n, a, b, c, f, g, h",
default="sin(u)*sin(v/8)+cos(v/8)*1.5")
z_eq = StringProperty(name="Z equation",
description="Equation for z=F(u,v). " \
"Also available: n, a, b, c, f, g, h",
default="sin(v)*(1+cos(u))*sin(v/8)")
range_u_min = FloatProperty(name="U min",
description="Minimum U value. Lower boundary of U range",
min=-100.00,
max=0.00,
default=0.00)
range_u_max = FloatProperty(name="U max",
description="Maximum U value. Upper boundary of U range",
min=0.00,
max=100.00,
default=2 * pi)
range_u_step = IntProperty(name="U step",
description="U Subdivisions",
min=1,
max=1024,
default=32)
wrap_u = BoolProperty(name="U wrap",
description="U Wrap around",
default=True)
range_v_min = FloatProperty(name="V min",
description="Minimum V value. Lower boundary of V range",
min=-100.00,
max=0.00,
default=0.00)
range_v_max = FloatProperty(name="V max",
description="Maximum V value. Upper boundary of V range",
min=0.00,
max=100.00,
default=4 * pi)
range_v_step = IntProperty(name="V step",
description="V Subdivisions",
min=1,
max=1024,
default=128)
wrap_v = BoolProperty(name="V wrap",
description="V Wrap around",
default=False)
close_v = BoolProperty(name="Close V",
description="Create faces for first and last " \
"V values (only if U is wrapped)",
default=False)
n_eq = IntProperty(name="Number of objects (n=0..N-1)",
description="The parameter n will be the index " \
"of the current object, 0 to N-1",
min=1,
max=100,
default=1)
a_eq = StringProperty(name="A helper function",
description="Equation for a=F(u,v). Also available: n",
default="0")
b_eq = StringProperty(name="B helper function",
description="Equation for b=F(u,v). Also available: n",
default="0")
c_eq = StringProperty(name="C helper function",
description="Equation for c=F(u,v). Also available: n",
default="0")
f_eq = StringProperty(name="F helper function",
description="Equation for f=F(u,v). Also available: n, a, b, c",
default="0")
g_eq = StringProperty(name="G helper function",
description="Equation for g=F(u,v). Also available: n, a, b, c",
default="0")
h_eq = StringProperty(name="H helper function",
description="Equation for h=F(u,v). Also available: n, a, b, c",
default="0")
x_eq = StringProperty(
name="X equation",
description="Equation for x=F(u,v). "
"Also available: n, a, b, c, f, g, h",
default="cos(v)*(1+cos(u))*sin(v/8)"
)
y_eq = StringProperty(
name="Y equation",
description="Equation for y=F(u,v). "
"Also available: n, a, b, c, f, g, h",
default="sin(u)*sin(v/8)+cos(v/8)*1.5"
)
z_eq = StringProperty(
name="Z equation",
description="Equation for z=F(u,v). "
"Also available: n, a, b, c, f, g, h",
default="sin(v)*(1+cos(u))*sin(v/8)"
)
range_u_min = FloatProperty(
name="U min",
description="Minimum U value. Lower boundary of U range",
min=-100.00,
max=0.00,
default=0.00
)
range_u_max = FloatProperty(
name="U max",
description="Maximum U value. Upper boundary of U range",
min=0.00,
max=100.00,
default=2 * pi
)
range_u_step = IntProperty(
name="U step",
description="U Subdivisions",
min=1,
max=1024,
default=32
)
wrap_u = BoolProperty(
name="U wrap",
description="U Wrap around",
default=True
)
range_v_min = FloatProperty(
name="V min",
description="Minimum V value. Lower boundary of V range",
min=-100.00,
max=0.00,
default=0.00
)
range_v_max = FloatProperty(
name="V max",
description="Maximum V value. Upper boundary of V range",
min=0.00,
max=100.00,
default=4 * pi
)
range_v_step = IntProperty(
name="V step",
description="V Subdivisions",
min=1,
max=1024,
default=128
)
wrap_v = BoolProperty(
name="V wrap",
description="V Wrap around",
default=False
)
close_v = BoolProperty(
name="Close V",
description="Create faces for first and last "
"V values (only if U is wrapped)",
default=False
)
n_eq = IntProperty(
name="Number of objects (n=0..N-1)",
description="The parameter n will be the index "
"of the current object, 0 to N-1",
min=1,
max=100,
default=1
)
a_eq = StringProperty(
name="A helper function",
description="Equation for a=F(u,v). Also available: n",
default="0"
)
b_eq = StringProperty(
name="B helper function",
description="Equation for b=F(u,v). Also available: n",
default="0"
)
c_eq = StringProperty(
name="C helper function",
description="Equation for c=F(u,v). Also available: n",
default="0"
)
f_eq = StringProperty(
name="F helper function",
description="Equation for f=F(u,v). Also available: n, a, b, c",
default="0"
)
g_eq = StringProperty(
name="G helper function",
description="Equation for g=F(u,v). Also available: n, a, b, c",
default="0"
)
h_eq = StringProperty(
name="H helper function",
description="Equation for h=F(u,v). Also available: n, a, b, c",
default="0"
)
def execute(self, context):
for n in range(0, self.n_eq):
verts, faces = xyz_function_surface_faces(
self,
self.x_eq,
@ -472,8 +520,8 @@ class AddXYZFunctionSurface(bpy.types.Operator):
self.g_eq,
self.h_eq,
n,
self.close_v)
self.close_v
)
if not verts:
return {'CANCELLED'}

View File

@ -1,38 +1,26 @@
################################################################################
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This is free software; you may redistribute it, and/or modify it,
# under the terms of the GNU General Public License.
#
# 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 (http://www.gnu.org/licenses/) for more details.
#
# ***** END GPL LICENSE BLOCK *****
'''
Create "Beam" primitives. Based on original script by revolt_randy.
'''
# Author(s): revolt_randy, Jambay
#
# GPL # "author": revolt_randy, Jambay
# Create "Beam" primitives. Based on original script by revolt_randy.
# @todo: track 3D cursor for location.
#
################################################################################
import bpy
from bpy.props import BoolProperty, EnumProperty, FloatProperty, FloatVectorProperty, IntProperty
from bpy.props import (
EnumProperty,
FloatProperty,
IntProperty,
)
from bpy_extras import object_utils
########################################
#
# #####################
# Create vertices for end of mesh
#
# y_off - verts y-axis origin
#
# returns:
# endVs - x,y,z list
#
def beamEndVs(sRef, y_off):
thick = sRef.beamW * 2
@ -63,15 +51,14 @@ def beamEndVs(sRef, y_off):
return endVs
########################################
#
# #####################
# Create End Faces
#
# verts_list - list of vertices
#
# returns:
# beamFs, a list of tuples defining the end faces.
#
def beamEndFaces(verts_list):
beamFs = []
@ -98,8 +85,7 @@ def beamEndFaces(verts_list):
return beamFs
########################################
#
# #####################
# Bridge vertices to create side faces.
#
# front_verts - front face vertices
@ -109,7 +95,7 @@ def beamEndFaces(verts_list):
#
# returns:
# sideFaces, a list of the bridged faces
#
def beamSides(front_verts, back_verts):
sideFaces = []
@ -127,14 +113,13 @@ def beamSides(front_verts, back_verts):
return sideFaces
####################################################
#
# #####################
# Creates a box beam
#
# returns:
# beamVs - x, y, z, location of each vertice
# beamFs - vertices that make up each face
#
def create_beam(sRef):
frontVs = []
@ -190,15 +175,14 @@ def create_beam(sRef):
return beamVs, beamFs
########################################
#
# #####################
# Taper/angle faces of beam.
# inner vert toward outer vert
# based on percentage of taper.
#
# returns:
# adVert - the calculated vertex
#
def beamSlant(sRef, outV, inV):
bTaper = 100 - sRef.edgeA
@ -209,15 +193,14 @@ def beamSlant(sRef, outV, inV):
return adVert
########################################
#
# #####################
# Modify location to shape beam.
#
# verts - tuples for one end of beam
#
# returns:
# verts - modified tuples for beam shape.
#
def beamSquareEnds(sRef, verts):
# match 5th & 6th z locations to 1st & 2nd
@ -235,7 +218,7 @@ def beamSquareEnds(sRef, verts):
return verts
########################################
# #####################
#
# Create U shaped beam
# Shared with C shape - see beamEndVs
@ -244,7 +227,7 @@ def beamSquareEnds(sRef, verts):
# returns:
# beamVs - vertice x, y, z, locations
# beamFs - face vertices
#
def create_u_beam(sRef):
# offset vertices from center
@ -308,12 +291,11 @@ def create_u_beam(sRef):
return beamVs, beamFs
###################################
#
# #####################
# returns:
# verts_final - x, y, z, location of each vertice
# faces_final - vertices that make up each face
#
def create_L_beam(sRef):
thick = sRef.beamW
@ -392,12 +374,11 @@ def create_L_beam(sRef):
return verts_final, faces_final
###################################
#
# #####################
# returns:
# verts_final - a list of tuples of the x, y, z, location of each vertice
# faces_final - a list of tuples of the vertices that make up each face
#
def create_T_beam(sRef):
thick = sRef.beamW
@ -513,12 +494,11 @@ def create_T_beam(sRef):
return verts_final, faces_final
###################################
#
# #####################
# returns:
# verts_final - a list of tuples of the x, y, z, location of each vertice
# faces_final - a list of tuples of the vertices that make up each face
#
def create_I_beam(sRef):
thick = sRef.beamW
@ -645,10 +625,10 @@ def create_I_beam(sRef):
return verts_final, faces_final
################################################################################
# ######################
#
# Generate beam object.
#
def addBeamObj(sRef, context):
verts = []
faces = []
@ -683,56 +663,75 @@ def addBeamObj(sRef, context):
bpy.ops.object.transform_apply(location=False, rotation=True, scale=False)
################################################################################
#
# ######################
# Create a beam primitive.
#
# UI functions and object creation.
#
class addBeam(bpy.types.Operator):
bl_idname = "mesh.add_beam"
bl_description = "Beam Builder"
bl_label = "Beam Builder"
bl_description = "Create beam meshes of various profiles"
bl_options = {'REGISTER', 'UNDO'}
Type = EnumProperty(items=(
('0', "Box", "Square Beam"),
("1", "U", "U Beam"),
("2", "C", "C Beam"),
("3", "L", "L Beam"),
("4", "I", "T Beam"),
("5", "T", "I Beam")
),
description="Beam form.")
Type = EnumProperty(
items=(
('0', "Box", "Square Beam"),
("1", "U", "U Beam"),
("2", "C", "C Beam"),
("3", "L", "L Beam"),
("4", "I", "T Beam"),
("5", "T", "I Beam")
),
description="Beam form."
)
beamZ = FloatProperty(
name="Height",
min=0.01, max=100,
default=1
)
beamX = FloatProperty(
name="Width",
min=0.01, max=100,
default=.5
)
beamY = FloatProperty(
name="Depth",
min=0.01,
max=100,
default=2
)
beamW = FloatProperty(
name="Thickness",
min=0.01, max=1,
default=0.1
)
edgeA = IntProperty(
name="Taper",
min=0, max=100,
default=0,
description="Angle beam edges"
)
beamZ = FloatProperty(name="Height", min=0.01, max=100, default=1)
beamX = FloatProperty(name="Width", min=0.01, max=100, default=.5)
beamY = FloatProperty(name="Depth", min=0.01, max=100, default=2)
beamW = FloatProperty(name="Thickness", min=0.01, max=1, default=0.1)
edgeA = IntProperty(name="Taper", min=0, max=100, default=0, description="Angle beam edges.")
########################################
def draw(self, context):
layout = self.layout
box = layout.box()
row = box.row()
row.prop(self, 'Type', text='')
row.prop(self, "Type", text="")
box.prop(self, 'beamZ')
box.prop(self, 'beamX')
box.prop(self, 'beamY')
box.prop(self, 'beamW')
box.prop(self, "beamZ")
box.prop(self, "beamX")
box.prop(self, "beamY")
box.prop(self, "beamW")
if self.Type != '0':
box.prop(self, 'edgeA')
box.prop(self, "edgeA")
########################################
def execute(self, context):
if bpy.context.mode == "OBJECT":
addBeamObj(self, context)
return {'FINISHED'}
else:
self.report({'WARNING'}, "Option only valid in Object mode")
return {'CANCELLED'}
self.report({'WARNING'}, "Option only valid in Object mode")
return {'CANCELLED'}

View File

@ -1,13 +1,19 @@
# GPL # (c) 2009, 2010 Michel J. Anders (varkenvarken)
import bpy
from math import *
from bpy.props import *
from bpy.types import Operator
from math import atan, asin, cos, sin, tan, pi, radians
from bpy.props import (
FloatProperty,
IntProperty,
)
# 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).
# 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)
@ -21,19 +27,20 @@ def create_mesh_object(context, verts, edges, faces, name):
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).
# 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.
# a fan/star of faces
# Note: If both vertex idx list are the same length they have
# to have at least 2 vertices.
# to have at least 2 vertices
def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False):
faces = []
@ -90,6 +97,7 @@ def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False):
return faces
# Calculate the vertex coordinates for a single
# section of a gear tooth.
# Returns 4 lists of vertex coords (list of tuples):
@ -160,9 +168,10 @@ def add_tooth(a, t, d, radius, Ad, De, base, p_angle, rack=0, crown=0.0):
return (verts_inner_base, verts_outer_base,
verts_middle_tooth, verts_tip_tooth)
# EXPERIMENTAL Calculate the vertex coordinates for a single
# section of a gearspoke.
# Returns them as a list of tuples.
# Returns them as a list of tuples
#
# a
# t
@ -181,7 +190,6 @@ def add_tooth(a, t, d, radius, Ad, De, base, p_angle, rack=0, crown=0.0):
def add_spoke(a, t, d, radius, De, base, s, w, l, gap=0, width=19):
Rd = radius - De
Rb = Rd - base
# Rl = Rb # UNUSED
verts = []
edgefaces = []
@ -216,29 +224,30 @@ def add_spoke(a, t, d, radius, De, base, s, w, l, gap=0, width=19):
return verts, edgefaces, edgefaces2, sf
# Create gear geometry.
# Returns:
# * A list of vertices (list of tuples)
# * A list of faces (list of lists)
# * A list (group) of vertices of the tip (list of vertex indices).
# * A list (group) of vertices of the valley (list of vertex indices).
# * A list (group) of vertices of the tip (list of vertex indices)
# * A list (group) of vertices of the valley (list of vertex indices)
#
# teethNum ... Number of teeth on the gear.
# teethNum ... Number of teeth on the gear
# radius ... Radius of the gear, negative for crown gear
# Ad ... Addendum, extent of tooth above radius.
# De ... Dedendum, extent of tooth below radius.
# base ... Base, extent of gear below radius.
# Ad ... Addendum, extent of tooth above radius
# De ... Dedendum, extent of tooth below radius
# base ... Base, extent of gear below radius
# p_angle ... Pressure angle. Skewness of tooth tip. (radiant)
# width ... Width, thickness of gear.
# width ... Width, thickness of gear
# skew ... Skew of teeth. (radiant)
# conangle ... Conical angle of gear. (radiant)
# rack
# crown ... Inward pointing extend of crown teeth.
# crown ... Inward pointing extend of crown teeth
#
# inner radius = radius - (De + base)
def add_gear(teethNum, radius, Ad, De, base, p_angle,
width=1, skew=0, conangle=0, rack=0, crown=0.0):
width=1, skew=0, conangle=0, rack=0, crown=0.0):
if teethNum < 2:
return None, None, None, None
@ -266,8 +275,7 @@ def add_gear(teethNum, radius, Ad, De, base, p_angle,
verts_outside_top = []
verts_outside_bottom = []
for (s, d, c, top) \
in [(0, -width, 1, True), \
(skew, width, scale, False)]:
in [(0, -width, 1, True), (skew, width, scale, False)]:
verts1, verts2, verts3, verts4 = add_tooth(a + s, t, d,
radius * c, Ad * c, De * c, base * c, p_angle,
@ -290,7 +298,7 @@ def add_gear(teethNum, radius, Ad, De, base, p_angle,
verts_outside.append(vertsIdx2[-1])
if top:
#verts_inside_top = vertsIdx1
# verts_inside_top = vertsIdx1
verts_outside_top = verts_outside
verts_bridge_start.append(vertsIdx1[0])
@ -299,7 +307,7 @@ def add_gear(teethNum, radius, Ad, De, base, p_angle,
verts_bridge_end.append(vertsIdx2[-1])
else:
#verts_inside_bottom = vertsIdx1
# verts_inside_bottom = vertsIdx1
verts_outside_bottom = verts_outside
verts_bridge_start.append(vertsIdx2[0])
@ -323,8 +331,8 @@ def add_gear(teethNum, radius, Ad, De, base, p_angle,
faces.extend(faces_tooth_middle_top)
faces.extend(faces_tooth_outer_top)
#faces_inside = createFaces(verts_inside_top, verts_inside_bottom)
#faces.extend(faces_inside)
# faces_inside = createFaces(verts_inside_top, verts_inside_bottom)
# faces.extend(faces_inside)
faces_outside = createFaces(verts_outside_top, verts_outside_bottom,
flipped=True)
@ -336,7 +344,6 @@ def add_gear(teethNum, radius, Ad, De, base, p_angle,
# Bridge one tooth to the next
if verts_bridge_prev:
faces_bridge = createFaces(verts_bridge_prev, verts_bridge_start)
#, closed=True (for "inside" faces)
faces.extend(faces_bridge)
# Remember "end" vertices for next tooth.
@ -344,21 +351,21 @@ def add_gear(teethNum, radius, Ad, De, base, p_angle,
# Bridge the first to the last tooth.
faces_bridge_f_l = createFaces(verts_bridge_prev, verts_bridge_first)
#, closed=True (for "inside" faces)
faces.extend(faces_bridge_f_l)
return verts, faces, vgroup_top, vgroup_valley
# Create spokes geometry.
# Create spokes geometry
# Returns:
# * A list of vertices (list of tuples)
# * A list of faces (list of lists)
#
# teethNum ... Number of teeth on the gear.
# radius ... Radius of the gear, negative for crown gear
# De ... Dedendum, extent of tooth below radius.
# base ... Base, extent of gear below radius.
# width ... Width, thickness of gear.
# De ... Dedendum, extent of tooth below radius
# base ... Base, extent of gear below radius
# width ... Width, thickness of gear
# conangle ... Conical angle of gear. (radiant)
# rack
# spoke
@ -369,10 +376,10 @@ def add_gear(teethNum, radius, Ad, De, base, p_angle,
#
# @todo Finish this
# @todo Create a function that takes a "Gear" and creates a
# matching "Gear Spokes" object.
# matching "Gear Spokes" object
def add_spokes(teethNum, radius, De, base, width=1, conangle=0, rack=0,
spoke=3, spbevel=0.1, spwidth=0.2, splength=1.0, spresol=9):
spoke=3, spbevel=0.1, spwidth=0.2, splength=1.0, spresol=9):
if teethNum < 2:
return None, None, None, None
@ -433,6 +440,7 @@ def add_spokes(teethNum, radius, De, base, width=1, conangle=0, rack=0,
return verts, faces
# Create worm geometry.
# Returns:
# * A list of vertices
@ -442,16 +450,17 @@ def add_spokes(teethNum, radius, De, base, width=1, conangle=0, rack=0,
#
# teethNum ... Number of teeth on the worm
# radius ... Radius of the gear, negative for crown gear
# Ad ... Addendum, extent of tooth above radius.
# De ... Dedendum, extent of tooth below radius.
# Ad ... Addendum, extent of tooth above radius
# De ... Dedendum, extent of tooth below radius
# p_angle ... Pressure angle. Skewness of tooth tip. (radiant)
# width ... Width, thickness of gear.
# crown ... Inward pointing extend of crown teeth.
# width ... Width, thickness of gear
# crown ... Inward pointing extend of crown teeth
#
# @todo: Fix teethNum. Some numbers are not possible yet.
# @todo: Fix teethNum. Some numbers are not possible yet
# @todo: Create start & end geoemtry (closing faces)
def add_worm(teethNum, rowNum, radius, Ad, De, p_angle,
width=1, skew=radians(11.25), crown=0.0):
width=1, skew=radians(11.25), crown=0.0):
worm = teethNum
teethNum = 24
@ -463,7 +472,7 @@ def add_worm(teethNum, rowNum, radius, Ad, De, p_angle,
vgroup_top = [] # Vertex group of top/tip? vertices.
vgroup_valley = [] # Vertex group of valley vertices
#width = width / 2.0
# width = width / 2.0
edgeloop_prev = []
for Row in range(rowNum):
@ -534,10 +543,11 @@ def add_worm(teethNum, rowNum, radius, Ad, De, p_angle,
return verts, faces, vgroup_top, vgroup_valley
class AddGear(bpy.types.Operator):
"""Add a gear mesh"""
class AddGear(Operator):
bl_idname = "mesh.primitive_gear"
bl_label = "Add Gear"
bl_description = "Construct a gear mesh"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
number_of_teeth = IntProperty(name="Number of Teeth",
@ -621,7 +631,6 @@ class AddGear(bpy.types.Operator):
box.prop(self, 'conangle')
box.prop(self, 'crown')
def execute(self, context):
verts, faces, verts_tip, verts_valley = add_gear(
self.number_of_teeth,
@ -633,7 +642,8 @@ class AddGear(bpy.types.Operator):
width=self.width,
skew=self.skew,
conangle=self.conangle,
crown=self.crown)
crown=self.crown
)
# Actually create the mesh object from this geometry data.
base = create_mesh_object(context, verts, [], faces, "Gear")
@ -650,79 +660,98 @@ class AddGear(bpy.types.Operator):
return {'FINISHED'}
class AddWormGear(bpy.types.Operator):
"""Add a worm gear mesh"""
class AddWormGear(Operator):
bl_idname = "mesh.primitive_worm_gear"
bl_label = "Add Worm Gear"
bl_description = "Construct a worm gear mesh"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
number_of_teeth = IntProperty(name="Number of Teeth",
description="Number of teeth on the gear",
min=2,
max=265,
default=12)
number_of_rows = IntProperty(name="Number of Rows",
description="Number of rows on the worm gear",
min=2,
max=265,
default=32)
radius = FloatProperty(name="Radius",
description="Radius of the gear, negative for crown gear",
min=-100.0,
max=100.0,
unit='LENGTH',
default=1.0)
addendum = FloatProperty(name="Addendum",
description="Addendum, extent of tooth above radius",
min=0.01,
max=100.0,
unit='LENGTH',
default=0.1)
dedendum = FloatProperty(name="Dedendum",
description="Dedendum, extent of tooth below radius",
min=0.0,
max=100.0,
unit='LENGTH',
default=0.1)
angle = FloatProperty(name="Pressure Angle",
description="Pressure angle, skewness of tooth tip",
min=0.0,
max=radians(45.0),
default=radians(20.0),
unit='ROTATION')
row_height = FloatProperty(name="Row Height",
description="Height of each Row",
min=0.05,
max=100.0,
unit='LENGTH',
default=0.2)
skew = FloatProperty(name="Skewness per Row",
description="Skew of each row",
min=radians(-90.0),
max=radians(90.0),
default=radians(11.25),
unit='ROTATION')
crown = FloatProperty(name="Crown",
description="Inward pointing extend of crown teeth",
min=0.0,
max=100.0,
unit='LENGTH',
default=0.0)
number_of_teeth = IntProperty(
name="Number of Teeth",
description="Number of teeth on the gear",
min=2,
max=265,
default=12
)
number_of_rows = IntProperty(
name="Number of Rows",
description="Number of rows on the worm gear",
min=2,
max=265,
default=32
)
radius = FloatProperty(
name="Radius",
description="Radius of the gear, negative for crown gear",
min=-100.0,
max=100.0,
unit='LENGTH',
default=1.0
)
addendum = FloatProperty(
name="Addendum",
description="Addendum, extent of tooth above radius",
min=0.01,
max=100.0,
unit='LENGTH',
default=0.1
)
dedendum = FloatProperty(
name="Dedendum",
description="Dedendum, extent of tooth below radius",
min=0.0,
max=100.0,
unit='LENGTH',
default=0.1
)
angle = FloatProperty(
name="Pressure Angle",
description="Pressure angle, skewness of tooth tip",
min=0.0,
max=radians(45.0),
default=radians(20.0),
unit='ROTATION'
)
row_height = FloatProperty(
name="Row Height",
description="Height of each Row",
min=0.05,
max=100.0,
unit='LENGTH',
default=0.2
)
skew = FloatProperty(
name="Skewness per Row",
description="Skew of each row",
min=radians(-90.0),
max=radians(90.0),
default=radians(11.25),
unit='ROTATION'
)
crown = FloatProperty(
name="Crown",
description="Inward pointing extend of crown teeth",
min=0.0,
max=100.0,
unit='LENGTH',
default=0.0
)
def draw(self, context):
layout = self.layout
box = layout.box()
box.prop(self, 'number_of_teeth')
box.prop(self, 'number_of_rows')
box.prop(self, 'radius')
box.prop(self, 'row_height')
box.prop(self, "number_of_teeth")
box.prop(self, "number_of_rows")
box.prop(self, "radius")
box.prop(self, "row_height")
box = layout.box()
box.prop(self, 'addendum')
box.prop(self, 'dedendum')
box.prop(self, "addendum")
box.prop(self, "dedendum")
box = layout.box()
box.prop(self, 'angle')
box.prop(self, 'skew')
box.prop(self, 'crown')
box.prop(self, "angle")
box.prop(self, "skew")
box.prop(self, "crown")
def execute(self, context):
@ -735,7 +764,8 @@ class AddWormGear(bpy.types.Operator):
self.angle,
width=self.row_height,
skew=self.skew,
crown=self.crown)
crown=self.crown
)
# Actually create the mesh object from this geometry data.
base = create_mesh_object(context, verts, [], faces, "Worm Gear")

View File

@ -1,14 +1,20 @@
# GPL # "author": "Pontiac, Fourmadmen, Dreampainter"
import bpy
from mathutils import *
from math import *
from bpy.props import *
from bpy.types import Operator
from mathutils import Vector, Quaternion
from math import cos, sin, pi
from bpy.props import (
FloatProperty,
IntProperty,
)
# 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).
# 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
@ -23,6 +29,7 @@ def create_mesh_object(context, verts, edges, faces, name):
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):
@ -44,7 +51,7 @@ def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False):
total = len(vertIdx2)
if closed:
# Bridge the start with the end.
# Bridge the start with the end
if flipped:
face = [
vertIdx1[0],
@ -61,7 +68,7 @@ def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False):
face.append(vertIdx2[total - 1])
faces.append(face)
# Bridge the rest of the faces.
# Bridge the rest of the faces
for num in range(total - 1):
if flipped:
if fan:
@ -80,6 +87,7 @@ def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False):
return faces
# @todo Clean up vertex&face creation process a bit.
def add_gem(r1, r2, seg, h1, h2):
"""
@ -139,8 +147,9 @@ def add_gem(r1, r2, seg, h1, h2):
return verts, faces
def add_diamond(segments, girdle_radius, table_radius,
crown_height, pavilion_height):
crown_height, pavilion_height):
PI_2 = pi * 2.0
z_axis = (0.0, 0.0, -1.0)
@ -192,37 +201,48 @@ def add_diamond(segments, girdle_radius, table_radius,
return verts, faces
class AddDiamond(bpy.types.Operator):
"""Add a diamond mesh"""
class AddDiamond(Operator):
bl_idname = "mesh.primitive_diamond_add"
bl_label = "Add Diamond"
bl_description = "Construct a diamond mesh"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
segments = IntProperty(name="Segments",
description="Number of segments for the diamond",
min=3,
max=256,
default=32)
girdle_radius = FloatProperty(name="Girdle Radius",
description="Girdle radius of the diamond",
min=0.01,
max=9999.0,
default=1.0)
table_radius = FloatProperty(name="Table Radius",
description="Girdle radius of the diamond",
min=0.01,
max=9999.0,
default=0.6)
crown_height = FloatProperty(name="Crown Height",
description="Crown height of the diamond",
min=0.01,
max=9999.0,
default=0.35)
pavilion_height = FloatProperty(name="Pavilion Height",
description="Pavilion height of the diamond",
min=0.01,
max=9999.0,
default=0.8)
segments = IntProperty(
name="Segments",
description="Number of segments for the diamond",
min=3,
max=256,
default=32
)
girdle_radius = FloatProperty(
name="Girdle Radius",
description="Girdle radius of the diamond",
min=0.01,
max=9999.0,
default=1.0
)
table_radius = FloatProperty(
name="Table Radius",
description="Girdle radius of the diamond",
min=0.01,
max=9999.0,
default=0.6
)
crown_height = FloatProperty(
name="Crown Height",
description="Crown height of the diamond",
min=0.01,
max=9999.0,
default=0.35
)
pavilion_height = FloatProperty(
name="Pavilion Height",
description="Pavilion height of the diamond",
min=0.01,
max=9999.0,
default=0.8
)
def execute(self, context):
verts, faces = add_diamond(self.segments,
@ -235,41 +255,50 @@ class AddDiamond(bpy.types.Operator):
return {'FINISHED'}
class AddGem(bpy.types.Operator):
"""Add a diamond gem"""
class AddGem(Operator):
bl_idname = "mesh.primitive_gem_add"
bl_label = "Add Gem"
bl_description = "Create an offset faceted gem"
bl_description = "Construct an offset faceted gem mesh"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
segments = IntProperty(name="Segments",
description="Longitudial segmentation",
min=3,
max=265,
default=8,)
pavilion_radius = FloatProperty(name="Radius",
description="Radius of the gem",
min=0.01,
max=9999.0,
default=1.0)
crown_radius = FloatProperty(name="Table Radius",
description="Radius of the table(top)",
min=0.01,
max=9999.0,
default=0.6)
crown_height = FloatProperty(name="Table height",
description="Height of the top half",
min=0.01,
max=9999.0,
default=0.35)
pavilion_height = FloatProperty(name="Pavilion height",
description="Height of bottom half",
min=0.01,
max=9999.0,
default=0.8)
segments = IntProperty(
name="Segments",
description="Longitudial segmentation",
min=3,
max=265,
default=8
)
pavilion_radius = FloatProperty(
name="Radius",
description="Radius of the gem",
min=0.01,
max=9999.0,
default=1.0
)
crown_radius = FloatProperty(
name="Table Radius",
description="Radius of the table(top)",
min=0.01,
max=9999.0,
default=0.6
)
crown_height = FloatProperty(
name="Table height",
description="Height of the top half",
min=0.01,
max=9999.0,
default=0.35
)
pavilion_height = FloatProperty(
name="Pavilion height",
description="Height of bottom half",
min=0.01,
max=9999.0,
default=0.8
)
def execute(self, context):
# create mesh
verts, faces = add_gem(
self.pavilion_radius,

View File

@ -1,6 +1,16 @@
# GPL # "author": "Kayo Phoenix"
import bpy
from bpy_extras import object_utils
from math import pi, sin, cos
from bpy.props import (
IntProperty,
BoolProperty,
BoolVectorProperty,
FloatProperty,
FloatVectorProperty,
)
class honeycomb_geometry():
def __init__(self, rows, cols, D, E):
@ -21,7 +31,6 @@ class honeycomb_geometry():
self.r = self.R - self.e
self.hr = 0.5 * self.r
self.H = self.R * (1.5 * self.rows + 0.5) + self.e
if self.rows > 1:
self.W = self.d * (self.cols + 0.5) + self.E
@ -41,47 +50,64 @@ class honeycomb_geometry():
def vert(self, row, col):
# full cell
if row >= 0 and row < self.rows and col >= 0 and col < self.cols: return [0, 1, 2, 3, 4, 5]
if row >= 0 and row < self.rows and col >= 0 and col < self.cols:
return [0, 1, 2, 3, 4, 5]
# right down corner
if row == -1 and col == self.cols - 1: return [1, 2]
if row == 0 and self.rows > 1 and col == self.cols: return [1, 2, 3]
if row == -1 and col == self.cols - 1:
return [1, 2]
if row == 0 and self.rows > 1 and col == self.cols:
return [1, 2, 3]
# left down corner
if row == -1 and col == -1: return [0, 1]
if row == -1 and col == -1:
return [0, 1]
if self.rows % 2:
# left up corner
if row == self.rows and col == -1: return [4, 5]
if row == self.rows and col == -1:
return [4, 5]
# right up corner
if row == self.rows and col == self.cols - 1: return [3, 4]
if row == self.rows - 1 and self.rows > 1 and col == self.cols: return [2, 3, 4]
if row == self.rows and col == self.cols - 1:
return [3, 4]
if row == self.rows - 1 and self.rows > 1 and col == self.cols:
return [2, 3, 4]
else:
# left up corner
if row == self.rows and col == 0: return [4, 5]
if row == self.rows - 1 and self.rows > 1 and col == -1: return [0, 4, 5]
if row == self.rows and col == 0:
return [4, 5]
if row == self.rows - 1 and self.rows > 1 and col == -1:
return [0, 4, 5]
# right up corner
if row == self.rows and col == self.cols: return [3, 4]
if row == self.rows and col == self.cols:
return [3, 4]
# horizontal lines
if col >= 0 and col < self.cols:
if row == -1: return [0, 1, 2]
if row == self.rows: return [3, 4, 5]
if row == -1:
return [0, 1, 2]
if row == self.rows:
return [3, 4, 5]
# vertical lines
if row >= 0 and row < self.rows:
if col == -1:
if row % 2: return [0, 1, 4, 5]
else: return [0, 5]
if row % 2:
return [0, 1, 4, 5]
else:
return [0, 5]
if col == self.cols:
if row % 2 or self.rows == 1: return [2, 3]
else: return [1, 2, 3, 4]
if row % 2 or self.rows == 1:
return [2, 3]
else:
return [1, 2, 3, 4]
return []
def cell(self, row, col, idx):
cp = [self.sx + self.dx * col, self.sy + self.dy * row, 0] # central point
if row % 2: cp[0] += self.gx
co = [] # vertexes coords
cp = [self.sx + self.dx * col, self.sy + self.dy * row, 0] # central point
if row % 2:
cp[0] += self.gx
co = [] # vertices coords
vi = self.vert(row, col)
ap = {}
for i in vi:
a = pi / 6 + i * pi / 3 # angle
a = pi / 6 + i * pi / 3 # angle
ap[i] = idx + len(co)
co.append((cp[0] + cos(a) * self.r, cp[1] + sin(a) * self.r, cp[2]))
return co, ap
@ -115,7 +141,8 @@ class honeycomb_geometry():
# top row
row = len(cells) - 1
cs = 0
if row % 2: cs += 1
if row % 2:
cs += 1
for col in range(1 + cs, len(cells[row]) - 1):
s = cells[row][col]
l = cells[row][col - 1]
@ -126,7 +153,8 @@ class honeycomb_geometry():
# middle rows
for row in range(1, len(cells) - 1):
cs = 0
if row % 2: cs += 1
if row % 2:
cs += 1
for col in range(1, len(cells[row]) - 1):
s = cells[row][col]
l = cells[row][col - 1]
@ -144,7 +172,8 @@ class honeycomb_geometry():
col = len(cells[row]) - 1
for row in range(1, len(cells) - 1):
cs = 0
if row % 2: cs += 1
if row % 2:
cs += 1
s = cells[row][col]
l = cells[row][col - 1]
@ -170,72 +199,78 @@ class honeycomb_geometry():
return verts, faces
import bpy
from bpy.props import *
from bpy_extras import object_utils
def edge_max(diam):
return diam * sin(pi / 3)
class add_mesh_honeycomb(bpy.types.Operator):
"""Simple honeycomb mesh generator"""
bl_idname = 'mesh.honeycomb_add'
bl_label = 'Add HoneyComb'
bl_idname = "mesh.honeycomb_add"
bl_label = "Add HoneyComb"
bl_description = "Simple honeycomb mesh generator"
bl_options = {'REGISTER', 'UNDO'}
rows = IntProperty(
name = 'Num of rows', default = 2,
min = 1, max = 100,
description='Number of the rows')
cols = IntProperty(
name = 'Num of cols', default = 2,
min = 1, max = 100,
description='Number of the columns')
layers = BoolVectorProperty(
name="Layers",
size=20,
subtype='LAYER',
options={'HIDDEN', 'SKIP_SAVE'},
)
def fix_edge(self, context):
m = edge_max(self.diam)
if self.edge > m: self.edge = m
if self.edge > m:
self.edge = m
rows = IntProperty(
name="Num of rows",
default=2,
min=1, max=100,
description='Number of the rows'
)
cols = IntProperty(
name='Num of cols',
default=2,
min=1, max=100,
description='Number of the columns'
)
layers = BoolVectorProperty(
name="Layers",
size=20,
subtype='LAYER',
options={'HIDDEN', 'SKIP_SAVE'},
)
diam = FloatProperty(
name = 'Cell Diameter', default = 1.0,
min = 0.0, update = fix_edge,
description='Diameter of the cell')
name='Cell Diameter',
default=1.0,
min=0.0, update=fix_edge,
description='Diameter of the cell'
)
edge = FloatProperty(
name = 'Edge Width', default = 0.1,
min = 0.0, update = fix_edge,
description='Width of the edge')
name='Edge Width',
default=0.1,
min=0.0, update=fix_edge,
description='Width of the edge'
)
# generic transform props
view_align = BoolProperty(
name="Align to View",
default=False)
name="Align to View",
default=False
)
location = FloatVectorProperty(
name="Location",
subtype='TRANSLATION')
name="Location",
subtype='TRANSLATION'
)
rotation = FloatVectorProperty(
name="Rotation",
subtype='EULER')
name="Rotation",
subtype='EULER'
)
##### POLL #####
@classmethod
def poll(cls, context):
return context.scene is not None
##### EXECUTE #####
def execute(self, context):
mesh = bpy.data.meshes.new(name='honeycomb')
comb = honeycomb_geometry(self.rows, self.cols, self.diam, self.edge)
verts, faces = comb.generate()
mesh.from_pydata(vertices = verts, edges = [], faces = faces)
mesh.from_pydata(vertices=verts, edges=[], faces=faces)
mesh.update()
object_utils.object_data_add(context, mesh, operator=self)

View File

@ -3,13 +3,18 @@
# This file is distributed under the MIT License. See the LICENSE.md for more details.
import bpy
from bpy.props import (
IntProperty,
BoolProperty,
BoolVectorProperty,
FloatVectorProperty,
FloatProperty,
)
from bpy.props import IntProperty, BoolProperty, BoolVectorProperty, FloatVectorProperty, FloatProperty
import bpy
import mathutils
import copy
class MengerSponge(object):
FACE_INDICES = [
[3, 7, 4, 0],
@ -111,13 +116,13 @@ class MengerSponge(object):
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)],
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:
@ -134,44 +139,43 @@ class MengerSponge(object):
class AddMengerSponge(bpy.types.Operator):
"""Add a menger sponge"""
bl_idname = "mesh.menger_sponge_add"
bl_label = "Menger Sponge"
bl_description = "Construct a menger sponge mesh"
bl_options = {'REGISTER', 'UNDO'}
level = IntProperty(
name="Level",
description="Sponge Level",
min=0, max=4,
default=1,
)
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,
)
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,
)
name="Align to View",
default=False,
)
location = FloatVectorProperty(
name="Location",
subtype='TRANSLATION',
)
name="Location",
subtype='TRANSLATION',
)
rotation = FloatVectorProperty(
name="Rotation",
subtype='EULER',
)
name="Rotation",
subtype='EULER',
)
layers = BoolVectorProperty(
name="Layers",
size=20,
subtype='LAYER',
options={'HIDDEN', 'SKIP_SAVE'},
)
name="Layers",
size=20,
subtype='LAYER',
options={'HIDDEN', 'SKIP_SAVE'},
)
def execute(self, context):
sponger = MengerSponge(self.level)
vertices, faces = sponger.create(self.radius * 2, self.radius * 2)
@ -182,7 +186,7 @@ class AddMengerSponge(bpy.types.Operator):
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]
uvloop.uv = uvs[i % 4]
from bpy_extras import object_utils
object_utils.object_data_add(context, mesh, operator=self)

View File

@ -1,13 +1,19 @@
# GPL # "author": "Buerbaum Martin (Pontiac)"
import bpy
from math import *
from bpy.props import *
from math import sin, cos, tan, pi, radians
from bpy.types import Operator
from bpy.props import (
FloatProperty,
IntProperty,
)
# 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).
# 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)
@ -21,6 +27,7 @@ def create_mesh_object(context, verts, edges, faces, name):
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):
@ -78,46 +85,55 @@ def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False):
return faces
class AddElbowJoint(bpy.types.Operator):
# Create the vertices and polygons for a simple elbow (bent pipe).
"""Add an Elbow pipe mesh"""
# Create the vertices and polygons for a simple elbow (bent pipe)
class AddElbowJoint(Operator):
bl_idname = "mesh.primitive_elbow_joint_add"
bl_label = "Add Pipe Elbow"
bl_description = "Construct an elbow pipe mesh"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
radius = FloatProperty(name="Radius",
radius = FloatProperty(
name="Radius",
description="The radius of the pipe",
default=1.0,
min=0.01,
max=100.0,
unit="LENGTH")
div = IntProperty(name="Divisions",
unit="LENGTH"
)
div = IntProperty(
name="Divisions",
description="Number of vertices (divisions)",
default=32, min=3, max=256)
angle = FloatProperty(name="Angle",
description="The angle of the branching pipe (i.e. the 'arm' - " \
default=32, min=3, max=256
)
angle = FloatProperty(
name="Angle",
description="The angle of the branching pipe (i.e. the 'arm' - "
"Measured from the center line of the main pipe",
default=radians(45.0),
min=radians(-179.9),
max=radians(179.9),
unit="ROTATION")
startLength = FloatProperty(name="Length Start",
unit="ROTATION"
)
startLength = FloatProperty(
name="Length Start",
description="Length of the beginning of the pipe",
default=3.0,
min=0.01,
max=100.0,
unit="LENGTH")
endLength = FloatProperty(name="End Length",
unit="LENGTH"
)
endLength = FloatProperty(
name="End Length",
description="Length of the end of the pipe",
default=3.0,
min=0.01,
max=100.0,
unit="LENGTH")
unit="LENGTH"
)
def execute(self, context):
radius = self.radius
div = self.div
@ -177,57 +193,68 @@ class AddElbowJoint(bpy.types.Operator):
return {'FINISHED'}
class AddTeeJoint(bpy.types.Operator):
# Create the vertices and polygons for a simple tee (T) joint.
# The base arm of the T can be positioned in an angle if needed though.
"""Add a Tee-Joint mesh"""
# Create the vertices and polygons for a simple tee (T) joint
# The base arm of the T can be positioned in an angle if needed though
class AddTeeJoint(Operator):
bl_idname = "mesh.primitive_tee_joint_add"
bl_label = "Add Pipe Tee-Joint"
bl_description = "Construct a tee-joint pipe mesh"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
radius = FloatProperty(name="Radius",
radius = FloatProperty(
name="Radius",
description="The radius of the pipe",
default=1.0,
min=0.01,
max=100.0,
unit="LENGTH")
div = IntProperty(name="Divisions",
unit="LENGTH"
)
div = IntProperty(
name="Divisions",
description="Number of vertices (divisions)",
default=32,
min=4,
max=256)
angle = FloatProperty(name="Angle",
description="The angle of the branching pipe (i.e. the 'arm' - " \
max=256
)
angle = FloatProperty(
name="Angle",
description="The angle of the branching pipe (i.e. the 'arm' - "
"Measured from the center line of the main pipe",
default=radians(90.0),
min=radians(0.1),
max=radians(179.9),
unit="ROTATION")
startLength = FloatProperty(name="Length Start",
description="Length of the beginning of the" \
unit="ROTATION"
)
startLength = FloatProperty(
name="Length Start",
description="Length of the beginning of the"
" main pipe (the straight one)",
default=3.0,
min=0.01,
max=100.0,
unit="LENGTH")
endLength = FloatProperty(name="End Length",
description="Length of the end of the" \
unit="LENGTH"
)
endLength = FloatProperty(
name="End Length",
description="Length of the end of the"
" main pipe (the straight one)",
default=3.0,
min=0.01,
max=100.0,
unit="LENGTH")
branchLength = FloatProperty(name="Arm Length",
unit="LENGTH"
)
branchLength = FloatProperty(
name="Arm Length",
description="Length of the arm pipe (the bent one)",
default=3.0,
min=0.01,
max=100.0,
unit="LENGTH")
unit="LENGTH"
)
def execute(self, context):
radius = self.radius
div = self.div
@ -238,24 +265,20 @@ class AddTeeJoint(bpy.types.Operator):
branchLength = self.branchLength
if (div % 2):
# Odd vertice number not supported (yet).
# Odd vertice number not supported (yet)
self.report({'INFO'}, "Odd vertices number is not yet supported")
return {'CANCELLED'}
verts = []
faces = []
# List of vert indices of each cross section
loopMainStart = [] # Vert indices for the
# beginning of the main pipe.
loopJoint1 = [] # Vert indices for joint that is used
# to connect the joint & loopMainStart.
loopJoint2 = [] # Vert indices for joint that is used
# to connect the joint & loopArm.
loopJoint3 = [] # Vert index for joint that is used
# to connect the joint & loopMainEnd.
loopArm = [] # Vert indices for the end of the arm.
loopMainEnd = [] # Vert indices for the
# end of the main pipe.
loopMainStart = [] # Vert indices for the beginning of the main pipe
loopJoint1 = [] # Vert indices for joint that is used to connect the joint & loopMainStart
loopJoint2 = [] # Vert indices for joint that is used to connect the joint & loopArm
loopJoint3 = [] # Vert index for joint that is used to connect the joint & loopMainEnd
loopArm = [] # Vert indices for the end of the arm
loopMainEnd = [] # Vert indices for the end of the main pipe.
# Create start circle (main pipe)
for vertIdx in range(div):
@ -355,61 +378,73 @@ class AddTeeJoint(bpy.types.Operator):
return {'FINISHED'}
class AddWyeJoint(bpy.types.Operator):
"""Add a Wye-Joint mesh"""
class AddWyeJoint(Operator):
bl_idname = "mesh.primitive_wye_joint_add"
bl_label = "Add Pipe Wye-Joint"
bl_description = "Construct a wye-joint pipe mesh"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
radius = FloatProperty(name="Radius",
radius = FloatProperty(
name="Radius",
description="The radius of the pipe",
default=1.0,
min=0.01,
max=100.0,
unit="LENGTH")
div = IntProperty(name="Divisions",
unit="LENGTH"
)
div = IntProperty(
name="Divisions",
description="Number of vertices (divisions)",
default=32,
min=4,
max=256)
angle1 = FloatProperty(name="Angle 1",
description="The angle of the 1. branching pipe " \
max=256
)
angle1 = FloatProperty(
name="Angle 1",
description="The angle of the 1. branching pipe "
"(measured from the center line of the main pipe)",
default=radians(45.0),
min=radians(-179.9),
max=radians(179.9),
unit="ROTATION")
angle2 = FloatProperty(name="Angle 2",
description="The angle of the 2. branching pipe " \
unit="ROTATION"
)
angle2 = FloatProperty(
name="Angle 2",
description="The angle of the 2. branching pipe "
"(measured from the center line of the main pipe) ",
default=radians(45.0),
min=radians(-179.9),
max=radians(179.9),
unit="ROTATION")
startLength = FloatProperty(name="Length Start",
description="Length of the beginning of the" \
unit="ROTATION"
)
startLength = FloatProperty(
name="Length Start",
description="Length of the beginning of the"
" main pipe (the straight one)",
default=3.0,
min=0.01,
max=100.0,
unit="LENGTH")
branch1Length = FloatProperty(name="Length Arm 1",
unit="LENGTH"
)
branch1Length = FloatProperty(
name="Length Arm 1",
description="Length of the 1. arm",
default=3.0,
min=0.01,
max=100.0,
unit="LENGTH")
branch2Length = FloatProperty(name="Length Arm 2",
unit="LENGTH"
)
branch2Length = FloatProperty(
name="Length Arm 2",
description="Length of the 2. arm",
default=3.0,
min=0.01,
max=100.0,
unit="LENGTH")
unit="LENGTH"
)
def execute(self, context):
radius = self.radius
div = self.div
@ -421,23 +456,20 @@ class AddWyeJoint(bpy.types.Operator):
branch2Length = self.branch2Length
if (div % 2):
# Odd vertice number not supported (yet).
# Odd vertice number not supported (yet)
self.report({'INFO'}, "Odd vertices number is not yet supported")
return {'CANCELLED'}
verts = []
faces = []
# List of vert indices of each cross section
loopMainStart = [] # Vert indices for
# the beginning of the main pipe.
loopJoint1 = [] # Vert index for joint that is used
# to connect the joint & loopMainStart.
loopJoint2 = [] # Vert index for joint that
# is used to connect the joint & loopArm1.
loopJoint3 = [] # Vert index for joint that is
# used to connect the joint & loopArm2.
loopArm1 = [] # Vert idxs for end of the 1. arm.
loopArm2 = [] # Vert idxs for end of the 2. arm.
loopMainStart = [] # Vert indices for the beginning of the main pipe
loopJoint1 = [] # Vert index for joint that is used to connect the joint & loopMainStart
loopJoint2 = [] # Vert index for joint that is used to connect the joint & loopArm1
loopJoint3 = [] # Vert index for joint that is used to connect the joint & loopArm2
loopArm1 = [] # Vert idxs for end of the 1. arm
loopArm2 = [] # Vert idxs for end of the 2. arm
# Create start circle
for vertIdx in range(div):
@ -480,11 +512,9 @@ class AddWyeJoint(bpy.types.Operator):
if (vertIdx > div / 2):
curVertAngle = vertIdx * (2.0 * pi / div)
locX = (-sin(curVertAngle) * sin(angleJoint)
/ sin(angle2 - angleJoint))
locX = (-sin(curVertAngle) * sin(angleJoint) / sin(angle2 - angleJoint))
locY = -cos(curVertAngle)
locZ = (-(sin(curVertAngle) * cos(angleJoint)
/ sin(angle2 - angleJoint)))
locZ = (-(sin(curVertAngle) * cos(angleJoint) / sin(angle2 - angleJoint)))
loopTemp.append(len(verts))
verts.append([locX * radius, locY * radius, locZ * radius])
@ -548,72 +578,86 @@ class AddWyeJoint(bpy.types.Operator):
return {'FINISHED'}
class AddCrossJoint(bpy.types.Operator):
"""Add a Cross-Joint mesh"""
# Create the vertices and polygons for a coss (+ or X) pipe joint.
# Create the vertices and polygons for a cross (+ or X) pipe joint
class AddCrossJoint(Operator):
bl_idname = "mesh.primitive_cross_joint_add"
bl_label = "Add Pipe Cross-Joint"
bl_description = "Construct a cross-joint pipe mesh"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
radius = FloatProperty(name="Radius",
radius = FloatProperty(
name="Radius",
description="The radius of the pipe",
default=1.0,
min=0.01,
max=100.0,
unit="LENGTH")
div = IntProperty(name="Divisions",
unit="LENGTH"
)
div = IntProperty(
name="Divisions",
description="Number of vertices (divisions)",
default=32,
min=4,
max=256)
angle1 = FloatProperty(name="Angle 1",
max=256
)
angle1 = FloatProperty(
name="Angle 1",
description="The angle of the 1. arm (from the main axis)",
default=radians(90.0),
min=radians(-179.9),
max=radians(179.9),
unit="ROTATION")
unit="ROTATION"
)
angle2 = FloatProperty(name="Angle 2",
description="The angle of the 2. arm (from the main axis)",
default=radians(90.0),
min=radians(-179.9),
max=radians(179.9),
unit="ROTATION")
unit="ROTATION"
)
angle3 = FloatProperty(name="Angle 3 (center)",
description="The angle of the center arm (from the main axis)",
default=radians(0.0),
min=radians(-179.9),
max=radians(179.9),
unit="ROTATION")
startLength = FloatProperty(name="Length Start",
description="Length of the beginning of the " \
unit="ROTATION"
)
startLength = FloatProperty(
name="Length Start",
description="Length of the beginning of the "
"main pipe (the straight one)",
default=3.0,
min=0.01,
max=100.0,
unit="LENGTH")
unit="LENGTH"
)
branch1Length = FloatProperty(name="Length Arm 1",
description="Length of the 1. arm",
default=3.0,
min=0.01,
max=100.0,
unit="LENGTH")
branch2Length = FloatProperty(name="Length Arm 2",
unit="LENGTH"
)
branch2Length = FloatProperty(
name="Length Arm 2",
description="Length of the 2. arm",
default=3.0,
min=0.01,
max=100.0,
unit="LENGTH")
branch3Length = FloatProperty(name="Length Arm 3 (center)",
unit="LENGTH"
)
branch3Length = FloatProperty(
name="Length Arm 3 (center)",
description="Length of the center arm",
default=3.0,
min=0.01,
max=100.0,
unit="LENGTH")
unit="LENGTH"
)
def execute(self, context):
radius = self.radius
div = self.div
@ -626,26 +670,22 @@ class AddCrossJoint(bpy.types.Operator):
branch2Length = self.branch2Length
branch3Length = self.branch3Length
if (div % 2):
# Odd vertice number not supported (yet).
# Odd vertice number not supported (yet)
self.report({'INFO'}, "Odd vertices number is not yet supported")
return {'CANCELLED'}
verts = []
faces = []
# List of vert indices of each cross section
loopMainStart = [] # Vert indices for the
# beginning of the main pipe.
loopJoint1 = [] # Vert index for joint that is used
# to connect the joint & loopMainStart.
loopJoint2 = [] # Vert index for joint that is used
# to connect the joint & loopArm1.
loopJoint3 = [] # Vert index for joint that is used
# to connect the joint & loopArm2.
loopJoint4 = [] # Vert index for joint that is used
# to connect the joint & loopArm3.
loopArm1 = [] # Vert idxs for the end of the 1. arm.
loopArm2 = [] # Vert idxs for the end of the 2. arm.
loopArm3 = [] # Vert idxs for the center arm end.
loopMainStart = [] # Vert indices for the beginning of the main pipe
loopJoint1 = [] # Vert index for joint that is used to connect the joint & loopMainStart
loopJoint2 = [] # Vert index for joint that is used to connect the joint & loopArm1
loopJoint3 = [] # Vert index for joint that is used to connect the joint & loopArm2
loopJoint4 = [] # Vert index for joint that is used to connect the joint & loopArm3
loopArm1 = [] # Vert idxs for the end of the 1. arm
loopArm2 = [] # Vert idxs for the end of the 2. arm
loopArm3 = [] # Vert idxs for the center arm end
# Create start circle
for vertIdx in range(div):
@ -681,8 +721,6 @@ class AddCrossJoint(bpy.types.Operator):
verts.append([locX * radius, locY * radius, locZ * radius])
# loopTemp2 = loopJoint2[:] # UNUSED
# Create 2. deformed joint circle
loopTempA = []
loopTempB = []
@ -693,7 +731,7 @@ class AddCrossJoint(bpy.types.Operator):
# Skip pole vertices
# @todo: This will possibly break if
# we ever support odd divisions.
# we ever support odd divisions
if not (vertIdx == 0) and not (vertIdx == div / 2):
if (vertIdx > div / 2):
@ -708,11 +746,9 @@ class AddCrossJoint(bpy.types.Operator):
Z = 1.0
loopTempB.append(len(verts))
locX = (sin(curVertAngle) * sin(angleJoint)
/ sin(angle - angleJoint))
locX = (sin(curVertAngle) * sin(angleJoint) / sin(angle - angleJoint))
locY = -cos(curVertAngle)
locZ = (Z * (sin(curVertAngle) * cos(angleJoint)
/ sin(angle - angleJoint)))
locZ = (Z * (sin(curVertAngle) * cos(angleJoint) / sin(angle - angleJoint)))
verts.append([locX * radius, locY * radius, locZ * radius])
@ -802,35 +838,45 @@ class AddCrossJoint(bpy.types.Operator):
return {'FINISHED'}
class AddNJoint(bpy.types.Operator):
"""Add a N-Joint mesh"""
# Create the vertices and polygons for a regular n-joint.
# Create the vertices and polygons for a regular n-joint
class AddNJoint(Operator):
bl_idname = "mesh.primitive_n_joint_add"
bl_label = "Add Pipe N-Joint"
bl_description = "Construct a n-joint pipe mesh"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
radius = FloatProperty(name="Radius",
radius = FloatProperty(
name="Radius",
description="The radius of the pipe",
default=1.0,
min=0.01,
max=100.0,
unit="LENGTH")
div = IntProperty(name="Divisions",
unit="LENGTH"
)
div = IntProperty(
name="Divisions",
description="Number of vertices (divisions)",
default=32,
min=4,
max=256)
number = IntProperty(name="Arms/Joints",
description="Number of joints/arms",
max=256
)
number = IntProperty(
name="Arms / Joints",
description="Number of joints / arms",
default=5,
min=2,
max=99999)
length = FloatProperty(name="Length",
description="Length of each joint/arm",
max=99999
)
length = FloatProperty(
name="Length",
description="Length of each joint / arm",
default=3.0,
min=0.01,
max=100.0,
unit="LENGTH")
unit="LENGTH"
)
def execute(self, context):
radius = self.radius
@ -839,7 +885,8 @@ class AddNJoint(bpy.types.Operator):
length = self.length
if (div % 2):
# Odd vertice number not supported (yet).
# Odd vertice number not supported (yet)
self.report({'INFO'}, "Odd vertices number is not yet supported")
return {'CANCELLED'}
if (number < 2):
@ -857,7 +904,7 @@ class AddNJoint(bpy.types.Operator):
angleDiv = (2.0 * pi / number)
# Create vertices for the end circles.
# Create vertices for the end circles
for num in range(number):
circle = []
# Create start circle
@ -882,7 +929,7 @@ class AddNJoint(bpy.types.Operator):
loopsEndCircles.append(circle)
# Create vertices for the joint circles.
# Create vertices for the joint circles
loopJoint = []
for vertIdx in range(div):
curVertAngle = vertIdx * (2.0 * pi / div)
@ -898,7 +945,7 @@ class AddNJoint(bpy.types.Operator):
skipVert = True
elif vertIdx == div / 2:
# @todo: This will possibly break if we
# ever support odd divisions.
# ever support odd divisions
if (num == 0):
vertTemp1 = len(verts)
else:
@ -930,7 +977,7 @@ class AddNJoint(bpy.types.Operator):
loopsJointsTemp.append(loopJoint)
# Create complete loops (loopsJoints) out of the
# double number of half loops in loopsJointsTemp.
# double number of half loops in loopsJointsTemp
for halfLoopIdx in range(len(loopsJointsTemp)):
if (halfLoopIdx == len(loopsJointsTemp) - 1):
idx1 = halfLoopIdx
@ -948,7 +995,7 @@ class AddNJoint(bpy.types.Operator):
loopsJoints.append(loopJoint)
# Create faces from the two
# loop arrays (loopsJoints -> loopsEndCircles).
# loop arrays (loopsJoints -> loopsEndCircles)
for loopIdx in range(len(loopsEndCircles)):
faces.extend(
createFaces(loopsJoints[loopIdx],

View File

@ -2,30 +2,33 @@
import bpy
import bmesh
from bpy.props import FloatProperty, IntProperty
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 create_step(width, base_level, step_height, num_sides):
axis = [0,0,-1]
axis = [0, 0, -1]
PI2 = pi * 2
rad = width / 2
quat_angles = [(cur_side/num_sides) * PI2
quat_angles = [(cur_side / num_sides) * PI2
for cur_side in range(num_sides)]
quaternions = [Quaternion(axis, quat_angle)
quaternions = [Quaternion(axis, quat_angle)
for quat_angle in quat_angles]
init_vectors = [Vector([rad, 0, base_level])] * len(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]
top_list = [(vec.x, vec.y, vec.z + step_height) for vec in vectors]
full_list = bottom_list + top_list
return full_list
@ -36,9 +39,8 @@ def split_list(l, n):
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)]
returned_list = [l[i: i + n] for i in range(0, len(l), n)]
return returned_list
def get_connector_pairs(lst, n_sides):
@ -48,87 +50,87 @@ def get_connector_pairs(lst, n_sides):
lst = split_list(lst, n_sides)
return lst
def add_pyramid_object(self, context):
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)
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]])
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(reversed(bm.verts[-self.num_sides:])) # otherwise normal faces intern... T44619.
# 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)
class AddPyramid(bpy.types.Operator, AddObjectHelper):
'''Add a mesh pyramid'''
bl_idname = "mesh.primitive_steppyramid_add"
bl_label = "Pyramid"
bl_description = "Construct a step pyramid mesh"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
num_sides = IntProperty(
name="Number Sides",
description = "How many sides each step will have",
min = 3, max = 20, default=4)
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)
min=1, max=20,
default=10
)
width = FloatProperty(
name="Initial Width",
description="Initial base step width",
min=0.01, max=100.0,
default=2)
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)
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)
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)
return {'FINISHED'}

View File

@ -3,204 +3,209 @@
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
from mathutils import Vector, Euler
from bpy.props import (
IntProperty,
FloatProperty,
BoolProperty,
)
# mesh/object generating function, returns final object
def addBrilliant(context, s, table_w, crown_h, girdle_t, pavi_d, bezel_f,
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
# # 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
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)
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
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))
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)
# upper girdle angle
uga = (1-bezel_f) * crown_h*2 / (ca2 -
(table_w + (1-table_w) * bezel_f) * ca2/ca)
# lower girdle angle
# 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)
lga = (1 - pavi_f) * pavi_d * 2 / (ca2 - pavi_f * ca2 / ca)
elif pavi_f == 1:
lga = 0
else:
lga = 2*pavi_d*ca
lga = 2 * pavi_d * ca
else:
lga = (1-pavi_f) * pavi_d*2 / (ca2 -
(culet + (1-culet) * pavi_f) * ca2/ca)
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)
va(1, 2 * girdle_t, ang, 0, s)
# append real girdle vertices
# append real girdle vertices
if girdle_real:
dnu = uga * (1 - ca2)
dfu = uga * (ta8 + ta4) * sa4
dnl = lga * (1 - ca2)
dnl = lga * (1 - ca2)
dfl = lga * (ta8 + ta4) * sa4
if abs(dnu) + abs(dnl) > 2*girdle_t or dnu < 0 or dnl < 0:
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)
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)
fa(i, i + s, 2 * i + 6 * s, 2 * i + 4 * s)
if i == 0:
fa(i, s, l1 - 1, 6*s - 1)
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)
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))
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 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))
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))
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)
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)
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))
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)
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))
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))
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))
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)
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)
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)
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, 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)
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))
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))
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)
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)
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 = []
@ -208,13 +213,13 @@ def addBrilliant(context, s, table_w, crown_h, girdle_t, pavi_d, bezel_f,
if i > l4 - 1:
cf.append(i)
fa(*cf)
# bpy variables / shortcuts
scene = bpy.context.scene
scene = bpy.context.scene
# deactivate possible active Objects
bpy.context.scene.objects.active = None
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)
@ -240,126 +245,146 @@ def addBrilliant(context, s, table_w, crown_h, girdle_t, pavi_d, bezel_f,
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')
bpy.ops.object.mode_set(mode='OBJECT')
pls = []
dp = obj.data.polygons[:4*s] # only consider faces of girdle
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
for i, face in enumerate(obj.data.polygons):
if i < 4 * s:
face.select = True
continue
face.select = False
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.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):
class MESH_OT_primitive_brilliant_add(Operator):
bl_idname = "mesh.primitive_brilliant_add"
bl_label = "Custom Brilliant"
bl_description = "Contruct a custom brilliant mesh"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
# set user options
s = IntProperty(name="Segments",
s = IntProperty(
name="Segments",
description="Longitudial segmentation",
step=1,
min=6,
max=128,
default=16,
subtype='FACTOR')
table_w = FloatProperty(name="Table width",
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",
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",
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",
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",
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",
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",
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",
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",
subtype='PERCENTAGE'
)
keep_lga = BoolProperty(
name="Retain lower angle",
description="If culet > 0, retains angle of pavillion facets",
default=False)
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)
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'}

View File

@ -4,14 +4,23 @@ import bpy
from bpy_extras import object_utils
from itertools import permutations
from math import copysign, pi, sqrt
from bpy.props import (
BoolProperty,
EnumProperty,
FloatProperty,
FloatVectorProperty,
IntProperty
)
def round_cube(radius=1.0, arcdiv=4, lindiv=0., size=(0. ,0. ,0.), div_type='CORNERS', odd_axis_align=False, info_only=False):
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
subdiv = CORNERS # fallback
radius = max(radius, 0.)
if not radius:
@ -28,7 +37,7 @@ def round_cube(radius=1.0, arcdiv=4, lindiv=0., size=(0. ,0. ,0.), div_type='COR
if not lindiv:
subdiv = CORNERS
odd = arcdiv % 2 # even = arcdiv % 2 ^ 1
odd = arcdiv % 2 # even = arcdiv % 2 ^ 1
step_size = 2. / arcdiv
odd_aligned = 0
@ -43,8 +52,8 @@ def round_cube(radius=1.0, arcdiv=4, lindiv=0., size=(0. ,0. ,0.), div_type='COR
if arcdiv == 1 and not odd_aligned and subdiv == EDGES:
subdiv = CORNERS
half_chord = 0. # ~ spherical cap base radius
sagitta = 0. # ~ spherical cap height
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)
@ -54,8 +63,8 @@ def round_cube(radius=1.0, arcdiv=4, lindiv=0., size=(0. ,0. ,0.), div_type='COR
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
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)
@ -78,22 +87,22 @@ def round_cube(radius=1.0, arcdiv=4, lindiv=0., size=(0. ,0. ,0.), div_type='COR
dvc += ec * ec // 2 * sum(dxyz) + ec * (ec - 1)
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)
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:
# Single vertex
return [(0,0,0)], []
return [(0, 0, 0)], []
# uv lookup table
uvlt = []
v = vi
for j in range(1, steps + 1):
v2 = v*v
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
v = vi + j * step_size # v += step_size # instead of accumulating errors
# clear fp errors / signs at axis
if abs(v) < 1e-10:
v = 0.0
@ -150,7 +159,7 @@ def round_cube(radius=1.0, arcdiv=4, lindiv=0., size=(0. ,0. ,0.), div_type='COR
svitc = svit[side]
exr = exyz[xp]
eyr = exyz[yp]
ri = 0 # row index
ri = 0 # row index
rij = zer if side < 4 else yer
if side == 5:
@ -161,16 +170,16 @@ def round_cube(radius=1.0, arcdiv=4, lindiv=0., size=(0. ,0. ,0.), div_type='COR
span = range(1, arcdiv)
ri = 1
for j in span: # rows
for j in span: # rows
v, v2, mv2 = uvlt[j]
tv2mh = 1./3. * v2 - 0.5
tv2mh = 1. / 3. * v2 - 0.5
hv2 = 0.5 * v2
if j == hemi and rij:
# Jump over non-edge row indices
ri += rij
for i in span: # columns
for i in span: # columns
u, u2, mu2 = uvlt[i]
vert[xp] = u * mv2
vert[yp] = v * mu2
@ -182,7 +191,7 @@ def round_cube(radius=1.0, arcdiv=4, lindiv=0., size=(0. ,0. ,0.), div_type='COR
rv = tuple(vert)
if exr and i == hemi:
rx = vert[xp] # save rotated x
rx = vert[xp] # save rotated x
vert[xp] = rxi = (-exr - half_chord) * dir[xp]
if axis_aligned:
svitc[ri].append(len(verts))
@ -216,7 +225,7 @@ def round_cube(radius=1.0, arcdiv=4, lindiv=0., size=(0. ,0. ,0.), div_type='COR
svitc[hemi + axis_aligned + l].append(len(verts))
verts.append(tuple(vert))
vert[yp] = ry
vert[xp] = rx # restore
vert[xp] = rx # restore
if eyr and j == hemi:
vert[yp] = (-eyr - half_chord) * dir[yp]
@ -276,122 +285,119 @@ def round_cube(radius=1.0, arcdiv=4, lindiv=0., size=(0. ,0. ,0.), div_type='COR
for side, rows in enumerate(svit):
xp, yp = sides[side][:2]
oa4 = odd_aligned and side == 4
if oa4: # special case
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)
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]))
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]))
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]))
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]))
faces.append((vi, rows[j + 1][i + 1], rows[j + 1][i]))
else:
faces.append((vi, row[i+1], rows[j+1][i]))
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]))
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]]))
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]]))
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]))
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, object_utils.AddObjectHelper):
"""Add Round Cube Primitive"""
bl_idname = 'mesh.primitive_round_cube_add'
bl_label = 'Add Round Cube'
bl_description = 'Add mesh primitives: Quadspheres, Capsules, Rounded Cuboids, 3D Grids, etc'
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
bl_idname = "mesh.primitive_round_cube_add"
bl_label = "Add Round Cube"
bl_description = ("Create mesh primitives: Quadspheres,"
"\nCapsules, Rounded Cuboids, 3D Grids etc.")
bl_options = {"REGISTER", "UNDO", "PRESET"}
sanity_check_verts = 200000
vert_count = 0
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
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',
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 = 1
name='Arc Divisions',
description='Arc curve divisions, per quadrant; 0=derive from Linear',
default=4, min=1
)
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
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 = (
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',
default='CORNERS',
)
odd_axis_align = BoolProperty(
name = 'Odd Axis Align',
description = 'Align odd arc divisions with axes (Note: triangle corners!)',
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)',
options = {'HIDDEN'}
name='No Limit',
description='Do not limit to ' + str(sanity_check_verts) + ' vertices (sanity check)',
options={'HIDDEN'}
)
def execute(self, context):
if self.arc_div <=0 and self.lin_div <= 0:
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:
if self.vert_count > self.sanity_check_verts:
self.report({'ERROR'}, 'More than '+str(self.sanity_check_verts)+' vertices! Check "No Limit" to proceed')
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)
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)
mesh.from_pydata(verts, [], faces)
object_utils.object_data_add(context, mesh, operator=self)
return {'FINISHED'}
def check(self, context):
self.arcdiv, self.lindiv, self.vert_count = round_cube(self.radius, self.arc_div, self.lin_div, self.size, self.div_type, self.odd_axis_align, True)
return True # False
self.arcdiv, self.lindiv, self.vert_count = round_cube(self.radius, self.arc_div, self.lin_div,
self.size, self.div_type, self.odd_axis_align, True)
return True
def invoke(self, context, event):
self.check(context)
@ -433,4 +439,3 @@ class AddRoundCube(bpy.types.Operator, object_utils.AddObjectHelper):
col = layout.column(align=True)
col.prop(self, 'rotation', expand=True)

View File

@ -1,25 +1,31 @@
# GPL # "author": "DreamPainter"
import bpy
from bpy.props import FloatProperty,EnumProperty,BoolProperty
from math import sqrt
from mathutils import Vector
from functools import reduce
from bpy.props import (
FloatProperty,
EnumProperty,
BoolProperty,
)
from bpy_extras.object_utils import object_data_add
# this function creates a chain of quads and, when necessary, a remaining tri
# for each polygon created in this script. be aware though, that this function
# assumes each polygon is convex.
# poly: list of faces, or a single face, like those
# needed for mesh.from_pydata.
# returns the tessellated faces.
def createPolys(poly):
# check for faces
if len(poly) == 0:
return []
# one or more faces
if type(poly[0]) == type(1):
poly = [poly] # if only one, make it a list of one face
poly = [poly] # if only one, make it a list of one face
faces = []
for i in poly:
L = len(i)
@ -28,20 +34,24 @@ def createPolys(poly):
faces.append(i)
# split all polygons in half and bridge the two halves
else:
f = [[i[x],i[x+1],i[L-2-x],i[L-1-x]] for x in range(L//2-1)]
f = [[i[x], i[x + 1], i[L - 2 - x], i[L - 1 - x]] for x in range(L // 2 - 1)]
faces.extend(f)
if L&1 == 1:
faces.append([i[L//2-1+x] for x in [0,1,2]])
if L & 1 == 1:
faces.append([i[L // 2 - 1 + x] for x in [0, 1, 2]])
return faces
# function to make the reduce function work as a workaround to sum a list of vectors
def vSum(list):
return reduce(lambda a,b: a+b, list)
return reduce(lambda a, b: a + b, list)
# creates the 5 platonic solids as a base for the rest
# plato: should be one of {"4","6","8","12","20"}. decides what solid the
# outcome will be.
# returns a list of vertices and faces
def source(plato):
verts = []
faces = []
@ -49,72 +59,74 @@ def source(plato):
# Tetrahedron
if plato == "4":
# Calculate the necessary constants
s = sqrt(2)/3.0
t = -1/3
u = sqrt(6)/3
s = sqrt(2) / 3.0
t = -1 / 3
u = sqrt(6) / 3
# create the vertices and faces
v = [(0,0,1),(2*s,0,t),(-s,u,t),(-s,-u,t)]
faces = [[0,1,2],[0,2,3],[0,3,1],[1,3,2]]
v = [(0, 0, 1), (2 * s, 0, t), (-s, u, t), (-s, -u, t)]
faces = [[0, 1, 2], [0, 2, 3], [0, 3, 1], [1, 3, 2]]
# Hexahedron (cube)
elif plato == "6":
# Calculate the necessary constants
s = 1/sqrt(3)
s = 1 / sqrt(3)
# create the vertices and faces
v = [(-s,-s,-s),(s,-s,-s),(s,s,-s),(-s,s,-s),(-s,-s,s),(s,-s,s),(s,s,s),(-s,s,s)]
faces = [[0,3,2,1],[0,1,5,4],[0,4,7,3],[6,5,1,2],[6,2,3,7],[6,7,4,5]]
v = [(-s, -s, -s), (s, -s, -s), (s, s, -s), (-s, s, -s), (-s, -s, s), (s, -s, s), (s, s, s), (-s, s, s)]
faces = [[0, 3, 2, 1], [0, 1, 5, 4], [0, 4, 7, 3], [6, 5, 1, 2], [6, 2, 3, 7], [6, 7, 4, 5]]
# Octahedron
elif plato == "8":
# create the vertices and faces
v = [(1,0,0),(-1,0,0),(0,1,0),(0,-1,0),(0,0,1),(0,0,-1)]
faces = [[4,0,2],[4,2,1],[4,1,3],[4,3,0],[5,2,0],[5,1,2],[5,3,1],[5,0,3]]
v = [(1, 0, 0), (-1, 0, 0), (0, 1, 0), (0, -1, 0), (0, 0, 1), (0, 0, -1)]
faces = [[4, 0, 2], [4, 2, 1], [4, 1, 3], [4, 3, 0], [5, 2, 0], [5, 1, 2], [5, 3, 1], [5, 0, 3]]
# Dodecahedron
elif plato == "12":
# Calculate the necessary constants
s = 1/sqrt(3)
t = sqrt((3-sqrt(5))/6)
u = sqrt((3+sqrt(5))/6)
s = 1 / sqrt(3)
t = sqrt((3 - sqrt(5)) / 6)
u = sqrt((3 + sqrt(5)) / 6)
# create the vertices and faces
v = [(s,s,s),(s,s,-s),(s,-s,s),(s,-s,-s),(-s,s,s),(-s,s,-s),(-s,-s,s),(-s,-s,-s),
(t,u,0),(-t,u,0),(t,-u,0),(-t,-u,0),(u,0,t),(u,0,-t),(-u,0,t),(-u,0,-t),(0,t,u),
(0,-t,u),(0,t,-u),(0,-t,-u)]
faces = [[0,8,9,4,16],[0,12,13,1,8],[0,16,17,2,12],[8,1,18,5,9],[12,2,10,3,13],
[16,4,14,6,17],[9,5,15,14,4],[6,11,10,2,17],[3,19,18,1,13],[7,15,5,18,19],
[7,11,6,14,15],[7,19,3,10,11]]
v = [(s, s, s), (s, s, -s), (s, -s, s), (s, -s, -s), (-s, s, s), (-s, s, -s), (-s, -s, s), (-s, -s, -s),
(t, u, 0), (-t, u, 0), (t, -u, 0), (-t, -u, 0), (u, 0, t), (u, 0, -t), (-u, 0, t), (-u, 0, -t), (0, t, u),
(0, -t, u), (0, t, -u), (0, -t, -u)]
faces = [[0, 8, 9, 4, 16], [0, 12, 13, 1, 8], [0, 16, 17, 2, 12], [8, 1, 18, 5, 9], [12, 2, 10, 3, 13],
[16, 4, 14, 6, 17], [9, 5, 15, 14, 4], [6, 11, 10, 2, 17], [3, 19, 18, 1, 13], [7, 15, 5, 18, 19],
[7, 11, 6, 14, 15], [7, 19, 3, 10, 11]]
# Icosahedron
elif plato == "20":
# Calculate the necessary constants
s = (1+sqrt(5))/2
t = sqrt(1+s*s)
s = s/t
t = 1/t
s = (1 + sqrt(5)) / 2
t = sqrt(1 + s * s)
s = s / t
t = 1 / t
# create the vertices and faces
v = [(s,t,0),(-s,t,0),(s,-t,0),(-s,-t,0),(t,0,s),(t,0,-s),(-t,0,s),(-t,0,-s),
(0,s,t),(0,-s,t),(0,s,-t),(0,-s,-t)]
faces = [[0,8,4],[0,5,10],[2,4,9],[2,11,5],[1,6,8],[1,10,7],[3,9,6],[3,7,11],
[0,10,8],[1,8,10],[2,9,11],[3,11,9],[4,2,0],[5,0,2],[6,1,3],[7,3,1],
[8,6,4],[9,4,6],[10,5,7],[11,7,5]]
v = [(s, t, 0), (-s, t, 0), (s, -t, 0), (-s, -t, 0), (t, 0, s), (t, 0, -s), (-t, 0, s), (-t, 0, -s),
(0, s, t), (0, -s, t), (0, s, -t), (0, -s, -t)]
faces = [[0, 8, 4], [0, 5, 10], [2, 4, 9], [2, 11, 5], [1, 6, 8], [1, 10, 7], [3, 9, 6], [3, 7, 11],
[0, 10, 8], [1, 8, 10], [2, 9, 11], [3, 11, 9], [4, 2, 0], [5, 0, 2], [6, 1, 3], [7, 3, 1],
[8, 6, 4], [9, 4, 6], [10, 5, 7], [11, 7, 5]]
# convert the tuples to Vectors
verts = [Vector(i) for i in v]
return verts,faces
return verts, faces
# processes the raw data from source
def createSolid(plato,vtrunc,etrunc,dual,snub):
def createSolid(plato, vtrunc, etrunc, dual, snub):
# the duals from each platonic solid
dualSource = {"4":"4",
"6":"8",
"8":"6",
"12":"20",
"20":"12"}
dualSource = {"4": "4",
"6": "8",
"8": "6",
"12": "20",
"20": "12"}
# constants saving space and readability
vtrunc *= 0.5
@ -126,25 +138,25 @@ def createSolid(plato,vtrunc,etrunc,dual,snub):
# no truncation
if vtrunc == 0:
if dual: # dual is as simple as another, but mirrored platonic solid
if dual: # dual is as simple as another, but mirrored platonic solid
vInput, fInput = source(dualSource[plato])
supposedSize = vSum(vInput[i] for i in fInput[0]).length/len(fInput[0])
vInput = [-i*supposedSize for i in vInput] # mirror it
supposedSize = vSum(vInput[i] for i in fInput[0]).length / len(fInput[0])
vInput = [-i * supposedSize for i in vInput] # mirror it
return vInput, fInput
return source(plato)
elif 0 < vtrunc <= 0.5: # simple truncation of the source
elif 0 < vtrunc <= 0.5: # simple truncation of the source
vInput, fInput = source(plato)
else:
# truncation is now equal to simple truncation of the dual of the source
vInput, fInput = source(dualSource[plato])
supposedSize = vSum(vInput[i] for i in fInput[0]).length / len(fInput[0])
vtrunc = 1-vtrunc # account for the source being a dual
if vtrunc == 0: # no truncation needed
vtrunc = 1 - vtrunc # account for the source being a dual
if vtrunc == 0: # no truncation needed
if dual:
vInput, fInput = source(plato)
vInput = [i*supposedSize for i in vInput]
vInput = [i * supposedSize for i in vInput]
return vInput, fInput
vInput = [-i*supposedSize for i in vInput]
vInput = [-i * supposedSize for i in vInput]
return vInput, fInput
# generate connection database
@ -153,141 +165,146 @@ def createSolid(plato,vtrunc,etrunc,dual,snub):
for x in range(len(fInput)):
i = fInput[x]
for j in range(len(i)):
vDict[i[j-1]][i[j]] = [i[j-2],x]
if len(vDict[i[j-1]]) == 1: vDict[i[j-1]][-1] = i[j]
vDict[i[j - 1]][i[j]] = [i[j - 2], x]
if len(vDict[i[j - 1]]) == 1:
vDict[i[j - 1]][-1] = i[j]
# the actual connection database: exists out of:
# [vtrunc pos, etrunc pos, connected vert IDs, connected face IDs]
vData = [[[],[],[],[]] for i in vInput]
fvOutput = [] # faces created from truncated vertices
feOutput = [] # faces created from truncated edges
vOutput = [] # newly created vertices
vData = [[[], [], [], []] for i in vInput]
fvOutput = [] # faces created from truncated vertices
feOutput = [] # faces created from truncated edges
vOutput = [] # newly created vertices
for x in range(len(vInput)):
i = vDict[x] # lookup the current vertex
i = vDict[x] # lookup the current vertex
current = i[-1]
while True: # follow the chain to get a ccw order of connected verts and faces
while True: # follow the chain to get a ccw order of connected verts and faces
vData[x][2].append(i[current][0])
vData[x][3].append(i[current][1])
# create truncated vertices
vData[x][0].append((1-vtrunc)*vInput[x] + vtrunc*vInput[vData[x][2][-1]])
vData[x][0].append((1 - vtrunc) * vInput[x] + vtrunc * vInput[vData[x][2][-1]])
current = i[current][0]
if current == i[-1]: break # if we're back at the first: stop the loop
fvOutput.append([]) # new face from truncated vert
fOffset = x*(len(i)-1) # where to start off counting faceVerts
if current == i[-1]:
break # if we're back at the first: stop the loop
fvOutput.append([]) # new face from truncated vert
fOffset = x * (len(i) - 1) # where to start off counting faceVerts
# only create one vert where one is needed (v1 todo: done)
if etrunc == 0.5:
for j in range(len(i)-1):
vOutput.append((vData[x][0][j]+vData[x][0][j-1])*etrunc) # create vert
fvOutput[x].append(fOffset+j) # add to face
fvOutput[x] = fvOutput[x][1:]+[fvOutput[x][0]] # rotate face for ease later on
for j in range(len(i) - 1):
vOutput.append((vData[x][0][j] + vData[x][0][j - 1]) * etrunc) # create vert
fvOutput[x].append(fOffset + j) # add to face
fvOutput[x] = fvOutput[x][1:] + [fvOutput[x][0]] # rotate face for ease later on
# create faces from truncated edges.
for j in range(len(i)-1):
if x > vData[x][2][j]: #only create when other vertex has been added
for j in range(len(i) - 1):
if x > vData[x][2][j]: # only create when other vertex has been added
index = vData[vData[x][2][j]][2].index(x)
feOutput.append([fvOutput[x][j],fvOutput[x][j-1],
feOutput.append([fvOutput[x][j], fvOutput[x][j - 1],
fvOutput[vData[x][2][j]][index],
fvOutput[vData[x][2][j]][index-1]])
fvOutput[vData[x][2][j]][index - 1]])
# edge truncation between none and full
elif etrunc > 0:
for j in range(len(i)-1):
for j in range(len(i) - 1):
# create snubs from selecting verts from rectified meshes
if rSnub:
vOutput.append(etrunc*vData[x][0][j]+(1-etrunc)*vData[x][0][j-1])
fvOutput[x].append(fOffset+j)
vOutput.append(etrunc * vData[x][0][j] + (1 - etrunc) * vData[x][0][j - 1])
fvOutput[x].append(fOffset + j)
elif lSnub:
vOutput.append((1-etrunc)*vData[x][0][j]+etrunc*vData[x][0][j-1])
fvOutput[x].append(fOffset+j)
else: #noSnub, select both verts from rectified mesh
vOutput.append(etrunc*vData[x][0][j]+(1-etrunc)*vData[x][0][j-1])
vOutput.append((1-etrunc)*vData[x][0][j]+etrunc*vData[x][0][j-1])
fvOutput[x].append(2*fOffset+2*j)
fvOutput[x].append(2*fOffset+2*j+1)
vOutput.append((1 - etrunc) * vData[x][0][j] + etrunc * vData[x][0][j - 1])
fvOutput[x].append(fOffset + j)
else: # noSnub, select both verts from rectified mesh
vOutput.append(etrunc * vData[x][0][j] + (1 - etrunc) * vData[x][0][j - 1])
vOutput.append((1 - etrunc) * vData[x][0][j] + etrunc * vData[x][0][j - 1])
fvOutput[x].append(2 * fOffset + 2 * j)
fvOutput[x].append(2 * fOffset + 2 * j + 1)
# rotate face for ease later on
if noSnub: fvOutput[x] = fvOutput[x][2:]+fvOutput[x][:2]
else: fvOutput[x] = fvOutput[x][1:]+[fvOutput[x][0]]
if noSnub:
fvOutput[x] = fvOutput[x][2:] + fvOutput[x][:2]
else:
fvOutput[x] = fvOutput[x][1:] + [fvOutput[x][0]]
# create single face for each edge
if noSnub:
for j in range(len(i)-1):
for j in range(len(i) - 1):
if x > vData[x][2][j]:
index = vData[vData[x][2][j]][2].index(x)
feOutput.append([fvOutput[x][j*2],fvOutput[x][2*j-1],
fvOutput[vData[x][2][j]][2*index],
fvOutput[vData[x][2][j]][2*index-1]])
feOutput.append([fvOutput[x][j * 2], fvOutput[x][2 * j - 1],
fvOutput[vData[x][2][j]][2 * index],
fvOutput[vData[x][2][j]][2 * index - 1]])
# create 2 tri's for each edge for the snubs
elif rSnub:
for j in range(len(i)-1):
for j in range(len(i) - 1):
if x > vData[x][2][j]:
index = vData[vData[x][2][j]][2].index(x)
feOutput.append([fvOutput[x][j],fvOutput[x][j-1],
feOutput.append([fvOutput[x][j], fvOutput[x][j - 1],
fvOutput[vData[x][2][j]][index]])
feOutput.append([fvOutput[x][j],fvOutput[vData[x][2][j]][index],
fvOutput[vData[x][2][j]][index-1]])
feOutput.append([fvOutput[x][j], fvOutput[vData[x][2][j]][index],
fvOutput[vData[x][2][j]][index - 1]])
elif lSnub:
for j in range(len(i)-1):
for j in range(len(i) - 1):
if x > vData[x][2][j]:
index = vData[vData[x][2][j]][2].index(x)
feOutput.append([fvOutput[x][j],fvOutput[x][j-1],
fvOutput[vData[x][2][j]][index-1]])
feOutput.append([fvOutput[x][j-1],fvOutput[vData[x][2][j]][index],
fvOutput[vData[x][2][j]][index-1]])
feOutput.append([fvOutput[x][j], fvOutput[x][j - 1],
fvOutput[vData[x][2][j]][index - 1]])
feOutput.append([fvOutput[x][j - 1], fvOutput[vData[x][2][j]][index],
fvOutput[vData[x][2][j]][index - 1]])
# special rules fro birectified mesh (v1 todo: done)
elif vtrunc == 0.5:
for j in range(len(i)-1):
if x < vData[x][2][j]: # use current vert, since other one has not passed yet
for j in range(len(i) - 1):
if x < vData[x][2][j]: # use current vert, since other one has not passed yet
vOutput.append(vData[x][0][j])
fvOutput[x].append(len(vOutput)-1)
fvOutput[x].append(len(vOutput) - 1)
else:
# search for other edge to avoid duplicity
connectee = vData[x][2][j]
fvOutput[x].append(fvOutput[connectee][vData[connectee][2].index(x)])
else: # vert truncation only
vOutput.extend(vData[x][0]) # use generated verts from way above
for j in range(len(i)-1): # create face from them
fvOutput[x].append(fOffset+j)
else: # vert truncation only
vOutput.extend(vData[x][0]) # use generated verts from way above
for j in range(len(i) - 1): # create face from them
fvOutput[x].append(fOffset + j)
# calculate supposed vertex length to ensure continuity
if supposedSize and not dual: # this to make the vtrunc > 1 work
supposedSize *= len(fvOutput[0])/vSum(vOutput[i] for i in fvOutput[0]).length
vOutput = [-i*supposedSize for i in vOutput]
supposedSize *= len(fvOutput[0]) / vSum(vOutput[i] for i in fvOutput[0]).length
vOutput = [-i * supposedSize for i in vOutput]
# create new faces by replacing old vert IDs by newly generated verts
ffOutput = [[] for i in fInput]
for x in range(len(fInput)):
# only one generated vert per vertex, so choose accordingly
# only one generated vert per vertex, so choose accordingly
if etrunc == 0.5 or (etrunc == 0 and vtrunc == 0.5) or lSnub or rSnub:
ffOutput[x] = [fvOutput[i][vData[i][3].index(x)-1] for i in fInput[x]]
ffOutput[x] = [fvOutput[i][vData[i][3].index(x) - 1] for i in fInput[x]]
# two generated verts per vertex
elif etrunc > 0:
for i in fInput[x]:
ffOutput[x].append(fvOutput[i][2*vData[i][3].index(x)-1])
ffOutput[x].append(fvOutput[i][2*vData[i][3].index(x)-2])
else: # cutting off corners also makes 2 verts
ffOutput[x].append(fvOutput[i][2 * vData[i][3].index(x) - 1])
ffOutput[x].append(fvOutput[i][2 * vData[i][3].index(x) - 2])
else: # cutting off corners also makes 2 verts
for i in fInput[x]:
ffOutput[x].append(fvOutput[i][vData[i][3].index(x)])
ffOutput[x].append(fvOutput[i][vData[i][3].index(x)-1])
ffOutput[x].append(fvOutput[i][vData[i][3].index(x) - 1])
if not dual:
return vOutput,fvOutput + feOutput + ffOutput
return vOutput, fvOutput + feOutput + ffOutput
else:
# do the same procedure as above, only now on the generated mesh
# do the same procedure as above, only now on the generated mesh
# generate connection database
vDict = [{} for i in vOutput]
dvOutput = [0 for i in fvOutput + feOutput + ffOutput]
dfOutput = []
for x in range(len(dvOutput)): # for every face
i = (fvOutput + feOutput + ffOutput)[x] # choose face to work with
for x in range(len(dvOutput)): # for every face
i = (fvOutput + feOutput + ffOutput)[x] # choose face to work with
# find vertex from face
normal = (vOutput[i[0]]-vOutput[i[1]]).cross(vOutput[i[2]]-vOutput[i[1]]).normalized()
dvOutput[x] = normal/(normal.dot(vOutput[i[0]]))
for j in range(len(i)): # create vert chain
vDict[i[j-1]][i[j]] = [i[j-2],x]
if len(vDict[i[j-1]]) == 1: vDict[i[j-1]][-1] = i[j]
normal = (vOutput[i[0]] - vOutput[i[1]]).cross(vOutput[i[2]] - vOutput[i[1]]).normalized()
dvOutput[x] = normal / (normal.dot(vOutput[i[0]]))
for j in range(len(i)): # create vert chain
vDict[i[j - 1]][i[j]] = [i[j - 2], x]
if len(vDict[i[j - 1]]) == 1:
vDict[i[j - 1]][-1] = i[j]
# calculate supposed size for continuity
supposedSize = vSum([vInput[i] for i in fInput[0]]).length/len(fInput[0])
supposedSize = vSum([vInput[i] for i in fInput[0]]).length / len(fInput[0])
supposedSize /= dvOutput[-1].length
dvOutput = [i*supposedSize for i in dvOutput]
dvOutput = [i * supposedSize for i in dvOutput]
# use chains to create faces
for x in range(len(vOutput)):
@ -297,10 +314,12 @@ def createSolid(plato,vtrunc,etrunc,dual,snub):
while True:
face.append(i[current][1])
current = i[current][0]
if current == i[-1]: break
if current == i[-1]:
break
dfOutput.append(face)
return dvOutput,dfOutput
return dvOutput, dfOutput
class Solids(bpy.types.Operator):
"""Add one of the (regular) solids (mesh)"""
@ -309,118 +328,134 @@ class Solids(bpy.types.Operator):
bl_description = "Add one of the Platonic, Archimedean or Catalan solids"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
source = EnumProperty(items = (("4","Tetrahedron",""),
("6","Hexahedron",""),
("8","Octahedron",""),
("12","Dodecahedron",""),
("20","Icosahedron","")),
name = "Source",
description = "Starting point of your solid")
size = FloatProperty(name = "Size",
description = "Radius of the sphere through the vertices",
min = 0.01,
soft_min = 0.01,
max = 100,
soft_max = 100,
default = 1.0)
vTrunc = FloatProperty(name = "Vertex Truncation",
description = "Ammount of vertex truncation",
min = 0.0,
soft_min = 0.0,
max = 2.0,
soft_max = 2.0,
default = 0.0,
precision = 3,
step = 0.5)
eTrunc = FloatProperty(name = "Edge Truncation",
description = "Ammount of edge truncation",
min = 0.0,
soft_min = 0.0,
max = 1.0,
soft_max = 1.0,
default = 0.0,
precision = 3,
step = 0.2)
snub = EnumProperty(items = (("None","No Snub",""),
("Left","Left Snub",""),
("Right","Right Snub","")),
name = "Snub",
description = "Create the snub version")
dual = BoolProperty(name="Dual",
description="Create the dual of the current solid",
default=False)
keepSize = BoolProperty(name="Keep Size",
description="Keep the whole solid at a constant size",
default=False)
preset = EnumProperty(items = (("0","Custom",""),
("t4","Truncated Tetrahedron",""),
("r4","Cuboctahedron",""),
("t6","Truncated Cube",""),
("t8","Truncated Octahedron",""),
("b6","Rhombicuboctahedron",""),
("c6","Truncated Cuboctahedron",""),
("s6","Snub Cube",""),
("r12","Icosidodecahedron",""),
("t12","Truncated Dodecahedron",""),
("t20","Truncated Icosahedron",""),
("b12","Rhombicosidodecahedron",""),
("c12","Truncated Icosidodecahedron",""),
("s12","Snub Dodecahedron",""),
("dt4","Triakis Tetrahedron",""),
("dr4","Rhombic Dodecahedron",""),
("dt6","Triakis Octahedron",""),
("dt8","Tetrakis Hexahedron",""),
("db6","Deltoidal Icositetrahedron",""),
("dc6","Disdyakis Dodecahedron",""),
("ds6","Pentagonal Icositetrahedron",""),
("dr12","Rhombic Triacontahedron",""),
("dt12","Triakis Icosahedron",""),
("dt20","Pentakis Dodecahedron",""),
("db12","Deltoidal Hexecontahedron",""),
("dc12","Disdyakis Triacontahedron",""),
("ds12","Pentagonal Hexecontahedron","")),
name = "Presets",
description = "Parameters for some hard names")
source = EnumProperty(
items=(("4", "Tetrahedron", ""),
("6", "Hexahedron", ""),
("8", "Octahedron", ""),
("12", "Dodecahedron", ""),
("20", "Icosahedron", "")),
name="Source",
description="Starting point of your solid"
)
size = FloatProperty(
name="Size",
description="Radius of the sphere through the vertices",
min=0.01,
soft_min=0.01,
max=100,
soft_max=100,
default=1.0
)
vTrunc = FloatProperty(
name="Vertex Truncation",
description="Ammount of vertex truncation",
min=0.0,
soft_min=0.0,
max=2.0,
soft_max=2.0,
default=0.0,
precision=3,
step=0.5
)
eTrunc = FloatProperty(
name="Edge Truncation",
description="Ammount of edge truncation",
min=0.0,
soft_min=0.0,
max=1.0,
soft_max=1.0,
default=0.0,
precision=3,
step=0.2
)
snub = EnumProperty(
items=(("None", "No Snub", ""),
("Left", "Left Snub", ""),
("Right", "Right Snub", "")),
name="Snub",
description="Create the snub version"
)
dual = BoolProperty(
name="Dual",
description="Create the dual of the current solid",
default=False
)
keepSize = BoolProperty(
name="Keep Size",
description="Keep the whole solid at a constant size",
default=False
)
preset = EnumProperty(
items=(("0", "Custom", ""),
("t4", "Truncated Tetrahedron", ""),
("r4", "Cuboctahedron", ""),
("t6", "Truncated Cube", ""),
("t8", "Truncated Octahedron", ""),
("b6", "Rhombicuboctahedron", ""),
("c6", "Truncated Cuboctahedron", ""),
("s6", "Snub Cube", ""),
("r12", "Icosidodecahedron", ""),
("t12", "Truncated Dodecahedron", ""),
("t20", "Truncated Icosahedron", ""),
("b12", "Rhombicosidodecahedron", ""),
("c12", "Truncated Icosidodecahedron", ""),
("s12", "Snub Dodecahedron", ""),
("dt4", "Triakis Tetrahedron", ""),
("dr4", "Rhombic Dodecahedron", ""),
("dt6", "Triakis Octahedron", ""),
("dt8", "Tetrakis Hexahedron", ""),
("db6", "Deltoidal Icositetrahedron", ""),
("dc6", "Disdyakis Dodecahedron", ""),
("ds6", "Pentagonal Icositetrahedron", ""),
("dr12", "Rhombic Triacontahedron", ""),
("dt12", "Triakis Icosahedron", ""),
("dt20", "Pentakis Dodecahedron", ""),
("db12", "Deltoidal Hexecontahedron", ""),
("dc12", "Disdyakis Triacontahedron", ""),
("ds12", "Pentagonal Hexecontahedron", "")),
name="Presets",
description="Parameters for some hard names"
)
# actual preset values
p = {"t4":["4",2/3,0,0,"None"],
"r4":["4",1,1,0,"None"],
"t6":["6",2/3,0,0,"None"],
"t8":["8",2/3,0,0,"None"],
"b6":["6",1.0938,1,0,"None"],
"c6":["6",1.0572,0.585786,0,"None"],
"s6":["6",1.0875,0.704,0,"Left"],
"r12":["12",1,0,0,"None"],
"t12":["12",2/3,0,0,"None"],
"t20":["20",2/3,0,0,"None"],
"b12":["12",1.1338,1,0,"None"],
"c12":["20",0.921,0.553,0,"None"],
"s12":["12",1.1235,0.68,0,"Left"],
"dt4":["4",2/3,0,1,"None"],
"dr4":["4",1,1,1,"None"],
"dt6":["6",2/3,0,1,"None"],
"dt8":["8",2/3,0,1,"None"],
"db6":["6",1.0938,1,1,"None"],
"dc6":["6",1.0572,0.585786,1,"None"],
"ds6":["6",1.0875,0.704,1,"Left"],
"dr12":["12",1,0,1,"None"],
"dt12":["12",2/3,0,1,"None"],
"dt20":["20",2/3,0,1,"None"],
"db12":["12",1.1338,1,1,"None"],
"dc12":["20",0.921,0.553,1,"None"],
"ds12":["12",1.1235,0.68,1,"Left"]}
p = {"t4": ["4", 2 / 3, 0, 0, "None"],
"r4": ["4", 1, 1, 0, "None"],
"t6": ["6", 2 / 3, 0, 0, "None"],
"t8": ["8", 2 / 3, 0, 0, "None"],
"b6": ["6", 1.0938, 1, 0, "None"],
"c6": ["6", 1.0572, 0.585786, 0, "None"],
"s6": ["6", 1.0875, 0.704, 0, "Left"],
"r12": ["12", 1, 0, 0, "None"],
"t12": ["12", 2 / 3, 0, 0, "None"],
"t20": ["20", 2 / 3, 0, 0, "None"],
"b12": ["12", 1.1338, 1, 0, "None"],
"c12": ["20", 0.921, 0.553, 0, "None"],
"s12": ["12", 1.1235, 0.68, 0, "Left"],
"dt4": ["4", 2 / 3, 0, 1, "None"],
"dr4": ["4", 1, 1, 1, "None"],
"dt6": ["6", 2 / 3, 0, 1, "None"],
"dt8": ["8", 2 / 3, 0, 1, "None"],
"db6": ["6", 1.0938, 1, 1, "None"],
"dc6": ["6", 1.0572, 0.585786, 1, "None"],
"ds6": ["6", 1.0875, 0.704, 1, "Left"],
"dr12": ["12", 1, 0, 1, "None"],
"dt12": ["12", 2 / 3, 0, 1, "None"],
"dt20": ["20", 2 / 3, 0, 1, "None"],
"db12": ["12", 1.1338, 1, 1, "None"],
"dc12": ["20", 0.921, 0.553, 1, "None"],
"ds12": ["12", 1.1235, 0.68, 1, "Left"]}
#previous preset, for User-friendly reasons
# previous preset, for User-friendly reasons
previousSetting = ""
def execute(self,context):
def execute(self, context):
# turn off undo for better performance (3-5x faster), also makes sure
# that mesh ops are undoable and entire script acts as one operator
bpy.context.user_preferences.edit.use_global_undo = False
# piece of code to make presets remain until parameters are changed
if self.preset != "0":
#if preset, set preset
# if preset, set preset
if self.previousSetting != self.preset:
using = self.p[self.preset]
self.source = using[0]
@ -434,7 +469,7 @@ class Solids(bpy.types.Operator):
result1 = abs(self.vTrunc - using[1]) < 0.004
result2 = abs(self.eTrunc - using[2]) < 0.0015
result4 = using[4] == self.snub or ((using[4] == "Left") and
self.snub in ["Left","Right"])
self.snub in ["Left", "Right"])
if (result0 and result1 and result2 and result4):
if self.p[self.previousSetting][3] != self.dual:
if self.preset[0] == "d":
@ -447,20 +482,22 @@ class Solids(bpy.types.Operator):
self.previousSetting = self.preset
# generate mesh
verts,faces = createSolid(self.source,
verts, faces = createSolid(self.source,
self.vTrunc,
self.eTrunc,
self.dual,
self.snub)
self.snub
)
# turn n-gons in quads and tri's
faces = createPolys(faces)
# resize to normal size, or if keepSize, make sure all verts are of length 'size'
if self.keepSize:
rad = self.size/verts[-1 if self.dual else 0].length
else: rad = self.size
verts = [i*rad for i in verts]
rad = self.size / verts[-1 if self.dual else 0].length
else:
rad = self.size
verts = [i * rad for i in verts]
# generate object
# Create new mesh

View File

@ -1,14 +1,19 @@
# GPL Original by Fourmadmen
import bpy
from mathutils import *
from math import *
from bpy.props import *
from mathutils import Vector, Quaternion
from math import pi
from bpy.props import (
IntProperty,
FloatProperty,
)
# 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).
# 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
@ -23,6 +28,7 @@ def create_mesh_object(context, verts, edges, faces, name):
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):
@ -68,14 +74,14 @@ def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False):
face = [vertIdx2[num], vertIdx1[0], vertIdx2[num + 1]]
else:
face = [vertIdx2[num], vertIdx1[num],
vertIdx1[num + 1], vertIdx2[num + 1]]
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]]
vertIdx2[num + 1], vertIdx1[num + 1]]
faces.append(face)
return faces
@ -121,8 +127,6 @@ def add_star(points, outer_radius, inner_radius, height):
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,
@ -134,32 +138,40 @@ def add_star(points, outer_radius, inner_radius, height):
return verts, faces
class AddStar(bpy.types.Operator):
"""Add a star mesh"""
bl_idname = "mesh.primitive_star_add"
bl_label = "Simple Star"
bl_description = "Construct a star mesh"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
points = IntProperty(name="Points",
points = IntProperty(
name="Points",
description="Number of points for the star",
min=2,
max=256,
default=5)
outer_radius = FloatProperty(name="Outer Radius",
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",
default=1.0
)
innter_radius = FloatProperty(
name="Inner Radius",
description="Inner radius of the star",
min=0.01,
max=9999.0,
default=0.5)
default=0.5
)
height = FloatProperty(name="Height",
description="Height of the star",
min=0.01,
max=9999.0,
default=0.5)
default=0.5
)
def execute(self, context):
@ -167,7 +179,8 @@ class AddStar(bpy.types.Operator):
self.points,
self.outer_radius,
self.innter_radius,
self.height)
self.height
)
obj = create_mesh_object(context, verts, [], faces, "Star")

View File

@ -1,15 +1,20 @@
# GPL # "author": "DreamPainter"
import bpy
from bpy.props import FloatProperty,BoolProperty,IntProperty
from bpy.props import (
FloatProperty,
BoolProperty,
IntProperty,
)
from math import pi, cos, sin
from mathutils import Vector
from bpy_extras import object_utils
# Create a new mesh (object) from verts/edges/faces.
# 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).
# 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
@ -24,7 +29,8 @@ def create_mesh_object(context, verts, edges, faces, name):
from bpy_extras import object_utils
return object_utils.object_data_add(context, mesh, operator=None)
# A very simple "bridge" tool.
# A very simple "bridge" tool
def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False):
faces = []
@ -82,12 +88,13 @@ def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False):
return faces
def power(a,b):
def power(a, b):
if a < 0:
return -((-a)**b)
return a**b
def supertoroid(R,r,u,v,n1,n2):
return -((-a) ** b)
return a ** b
def supertoroid(R, r, u, v, n1, n2):
"""
R = big radius
r = small radius
@ -96,99 +103,121 @@ def supertoroid(R,r,u,v,n1,n2):
n1 = value determines the shape of the torus
n2 = value determines the shape of the cross-section
"""
# create the necessary constants
a = 2*pi/u
b = 2*pi/v
a = 2 * pi / u
b = 2 * pi / v
verts = []
faces = []
# create each cross-section by calculating each vector on the
# create each cross-section by calculating each vector on the
# the wannabe circle
# x = (cos(theta)**n1)*(R+r*(cos(phi)**n2))
# y = (sin(theta)**n1)*(R+r*(cos(phi)**n2))
# z = (r*sin(phi)**n2)
# x = (cos(theta) ** n1)*(R + r * (cos(phi) ** n2))
# y = (sin(theta) ** n1)*(R + r * (cos(phi) ** n2))
# z = (r * sin(phi) ** n2)
# with theta and phi rangeing from 0 to 2pi
for i in range(u):
s = power(sin(i*a),n1)
c = power(cos(i*a),n1)
s = power(sin(i * a), n1)
c = power(cos(i * a), n1)
for j in range(v):
c2 = R+r*power(cos(j*b),n2)
s2 = r*power(sin(j*b),n2)
verts.append(Vector((c*c2,s*c2,s2)))
c2 = R + r * power(cos(j * b), n2)
s2 = r * power(sin(j * b), n2)
verts.append(Vector((c * c2, s * c2, s2)))
# bridge the last circle with the previous circle
if i > 0: # but not for the first circle, 'cus there's no previous before the first
f = createFaces(range((i-1)*v,i*v),range(i*v,(i+1)*v),closed = True)
f = createFaces(range((i - 1) * v, i * v), range(i * v, (i + 1) * v), closed=True)
faces.extend(f)
# bridge the last circle with the first
f = createFaces(range((u-1)*v,u*v),range(v),closed=True)
f = createFaces(range((u - 1) * v, u * v), range(v), closed=True)
faces.extend(f)
return verts, faces
class add_supertoroid(bpy.types.Operator):
"""Add a SuperToroid"""
bl_idname = "mesh.primitive_supertoroid_add"
bl_label = "Add SuperToroid"
bl_description = "Create a SuperToroid"
bl_description = "Construct a supertoroid mesh"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
R = FloatProperty(name = "big radius",
description = "The radius inside the tube",
default = 1.0, min = 0.01, max = 100.0)
r = FloatProperty(name = "small radius",
description = "The radius of the tube",
default = 0.3, min = 0.01, max = 100.0)
u = IntProperty(name = "U-segments",
description = "radial segmentation",
default = 16, min = 3, max = 265)
v = IntProperty(name = "V-segments",
description = "lateral segmentation",
default = 8, min = 3, max = 265)
n1 = FloatProperty(name = "Ring manipulator",
description = "Manipulates the shape of the Ring",
default = 1.0, min = 0.01, max = 100.0)
n2 = FloatProperty(name = "Cross manipulator",
description = "Manipulates the shape of the cross-section",
default = 1.0, min = 0.01, max = 100.0)
ie = BoolProperty(name = "Use Int.+Ext. radii",
description = "Use internal and external radii",
default = False)
edit = BoolProperty(name="",
description="",
default=False,
options={'HIDDEN'})
R = FloatProperty(
name="Big radius",
description="The radius inside the tube",
default=1.0,
min=0.01, max=100.0
)
r = FloatProperty(
name="Small radius",
description="The radius of the tube",
default=0.3,
min=0.01, max=100.0
)
u = IntProperty(
name="U-segments",
description="Radial segmentation",
default=16,
min=3, max=265
)
v = IntProperty(
name="V-segments",
description="Lateral segmentation",
default=8,
min=3, max=265
)
n1 = FloatProperty(
name="Ring manipulator",
description="Manipulates the shape of the Ring",
default=1.0,
min=0.01, max=100.0
)
n2 = FloatProperty(
name="Cross manipulator",
description="Manipulates the shape of the cross-section",
default=1.0,
min=0.01, max=100.0
)
ie = BoolProperty(
name="Use Int. and Ext. radii",
description="Use internal and external radii",
default=False
)
edit = BoolProperty(
name="",
description="",
default=False,
options={'HIDDEN'}
)
def execute(self,context):
def execute(self, context):
props = self.properties
# check how the radii properties must be used
if props.ie:
rad1 = (props.R+props.r)/2
rad2 = (props.R-props.r)/2
rad1 = (props.R + props.r) / 2
rad2 = (props.R - props.r) / 2
# for consistency in the mesh, ie no crossing faces, make the largest of the two
# the outer radius
if rad2 > rad1:
[rad1,rad2] = [rad2,rad1]
[rad1, rad2] = [rad2, rad1]
else:
rad1 = props.R
rad2 = props.r
# again for consistency, make the radius in the tube,
# again for consistency, make the radius in the tube,
# at least as big as the radius of the tube
if rad2 > rad1:
rad1 = rad2
# create mesh
verts,faces = supertoroid(rad1,
verts, faces = supertoroid(rad1,
rad2,
props.u,
props.v,
props.n1,
props.n2)
props.n2
)
# create the object
obj = create_mesh_object(context, verts, [], faces, "SuperToroid")
return {'FINISHED'}

View File

@ -1,7 +1,10 @@
# GPL # Author, Anthony D'Agostino
import bpy
from bpy.props import IntProperty
from bpy.props import (
IntProperty,
EnumProperty,
)
import mathutils
@ -9,21 +12,26 @@ import io
import operator
import functools
class AddTeapot(bpy.types.Operator):
"""Add a teapot mesh"""
bl_idname = "mesh.primitive_teapot_add"
bl_label = "Add Teapot"
bl_description = "Construct a teapot or teaspoon mesh"
bl_options = {"REGISTER", "UNDO"}
resolution = IntProperty(
name="Resolution",
description="Resolution of the Teapot",
default=5, min=2, max=15,
default=5,
min=2, max=15,
)
objecttype = IntProperty(
objecttype = EnumProperty(
name="Object Type",
description="Type of Bezier Object",
default=1, min=1, max=2)
items=(('1', "Teapot", "Construct a teapot mesh"),
('2', "Tea Spoon", "Construct a teaspoon mesh")),
default='1',
)
def execute(self, context):
verts, faces = make_teapot(self.objecttype,
@ -32,6 +40,7 @@ class AddTeapot(bpy.types.Operator):
obj = create_mesh_object(context, verts, [], faces, "Teapot")
return {'FINISHED'}
def create_mesh_face_hack(faces):
# FIXME, faces with duplicate vertices shouldn't be created in the first place.
faces_copy = []
@ -43,6 +52,7 @@ def create_mesh_face_hack(faces):
faces_copy.append(f_copy)
faces[:] = faces_copy
def create_mesh_object(context, verts, edges, faces, name):
create_mesh_face_hack(faces)
@ -60,6 +70,7 @@ def create_mesh_object(context, verts, edges, faces, name):
# ==========================
# === Bezier patch Block ===
# ==========================
def read_indexed_patch_file(filename):
file = io.StringIO(filename)
rawpatches = []
@ -81,7 +92,7 @@ def read_indexed_patch_file(filename):
v1, v2, v3 = map(float, line.split(","))
verts.append((v1, v2, v3))
for i in range(len(patches)):
for j in range(4): # len(patches[i])):
for j in range(4): # len(patches[i])):
for k in range(4): # len(patches[i][j])):
index = patches[i][j][k] - 1
rawpatches[i][j][k] = verts[index]
@ -109,7 +120,7 @@ def make_bezier(ctrlpnts, resolution):
def makevert(t):
x, y, z = b1(t) * p1 + b2(t) * p2 + b3(t) * p3 + b4(t) * p4
return (x, y, z)
curveverts = [makevert(i/resolution) for i in range(resolution+1)]
curveverts = [makevert(i / resolution) for i in range(resolution + 1)]
return curveverts
@ -178,14 +189,21 @@ def transpose(rowsbycols):
return colsbyrows
def make_teapot(filename, resolution):
def make_teapot(enumname, resolution):
filenames = [None, teapot, teaspoon]
filename = filenames[filename]
try:
indexs = int(enumname)
filename = filenames[indexs]
except:
print("Add Teapot Error: EnumProperty could not be set")
filename = filenames[1]
patches = read_indexed_patch_file(filename)
raw = patches_to_raw(patches, resolution)
verts, faces = raw_to_indexed(raw)
return (verts, faces)
# =================================
# === Indexed Bezier Data Block ===
# =================================

View File

@ -1,6 +1,10 @@
# GPL # Author, Anthony D'Agostino
import bpy, mathutils, math
import bpy
from mathutils import Vector
from math import sin, cos, pi
from bpy.props import IntProperty
def create_mesh_object(context, verts, edges, faces, name):
# Create new mesh
@ -12,90 +16,103 @@ def create_mesh_object(context, verts, edges, faces, name):
from bpy_extras import object_utils
return object_utils.object_data_add(context, mesh, operator=None)
# ========================
# === Torus Knot Block ===
# ========================
def k1(t):
x = math.cos(t) - 2*math.cos(2*t)
y = math.sin(t) + 2*math.sin(2*t)
z = math.sin(3*t)
return mathutils.Vector([x,y,z])
x = cos(t) - 2 * cos(2 * t)
y = sin(t) + 2 * sin(2 * t)
z = sin(3 * t)
return Vector([x, y, z])
def k2(t):
x = 10 * (math.cos(t) + math.cos(3*t)) + math.cos(2*t) + math.cos(4*t)
y = 6 * math.sin(t) + 10 * math.sin(3*t)
z = 4 * math.sin(3*t) * math.sin(5*t/2) + 4*math.sin(4*t) - 2*math.sin(6*t)
return mathutils.Vector([x,y,z]) * 0.2
x = 10 * (cos(t) + cos(3 * t)) + cos(2 * t) + cos(4 * t)
y = 6 * sin(t) + 10 * sin(3 * t)
z = 4 * sin(3 * t) * sin(5 * t / 2) + 4 * sin(4 * t) - 2 * sin(6 * t)
return Vector([x, y, z]) * 0.2
def k3(t):
x = 2.5*math.cos(t+math.pi)/3 + 2*math.cos(3*t)
y = 2.5*math.sin(t)/3 + 2*math.sin(3*t)
z = 1.5*math.sin(4*t) + math.sin(2*t)/3
return mathutils.Vector([x,y,z])
x = 2.5 * cos(t + pi) / 3 + 2 * cos(3 * t)
y = 2.5 * sin(t) / 3 + 2 * sin(3 * t)
z = 1.5 * sin(4 * t) + sin(2 * t) / 3
return Vector([x, y, z])
def make_verts(ures, vres, r2, knotfunc):
verts = []
for i in range(ures):
t1 = (i+0) * 2*math.pi/ures
t2 = (i+1) * 2*math.pi/ures
a = knotfunc(t1) # curr point
b = knotfunc(t2) # next point
a,b = map(mathutils.Vector, (a,b))
e = a-b
f = a+b
g = e.cross(f)
h = e.cross(g)
g.normalize()
h.normalize()
for j in range(vres):
k = j * 2*math.pi/vres
l = (math.cos(k),0.0,math.sin(k))
l = mathutils.Vector(l)
m = l * r2
x,y,z = m
n = h*x
o = g*z
p = n+o
q = a+p
verts.append(q)
return verts
verts = []
for i in range(ures):
t1 = (i + 0) * 2 * pi / ures
t2 = (i + 1) * 2 * pi / ures
a = knotfunc(t1) # curr point
b = knotfunc(t2) # next point
a, b = map(Vector, (a, b))
e = a - b
f = a + b
g = e.cross(f)
h = e.cross(g)
g.normalize()
h.normalize()
for j in range(vres):
k = j * 2 * pi / vres
l = (cos(k), 0.0, sin(k))
l = Vector(l)
m = l * r2
x, y, z = m
n = h * x
o = g * z
p = n + o
q = a + p
verts.append(q)
return verts
def make_faces(ures, vres):
faces = []
for u in range(0, ures):
for v in range(0, vres):
p1 = v + u*vres
p2 = v + ((u+1)%ures)*vres
p4 = (v+1)%vres + u*vres
p3 = (v+1)%vres + ((u+1)%ures)*vres
faces.append([p4, p3, p2, p1])
return faces
faces = []
for u in range(0, ures):
for v in range(0, vres):
p1 = v + u * vres
p2 = v + ((u + 1) % ures) * vres
p4 = (v + 1) % vres + u * vres
p3 = (v + 1) % vres + ((u + 1) % ures) * vres
faces.append([p4, p3, p2, p1])
return faces
def make_knot(knotidx, ures):
knots = [k1,k2,k3]
knotfunc = knots[knotidx-1]
vres = ures//10
r2 = 0.5
verts = make_verts(ures, vres, r2, knotfunc)
faces = make_faces(ures, vres)
return (verts, faces)
knots = [k1, k2, k3]
knotfunc = knots[knotidx - 1]
vres = ures // 10
r2 = 0.5
verts = make_verts(ures, vres, r2, knotfunc)
faces = make_faces(ures, vres)
return (verts, faces)
class AddTorusKnot(bpy.types.Operator):
"""Add a torus-knot mesh"""
bl_idname = "mesh.primitive_torusknot_add"
bl_label = "Add Torus Knot"
bl_options = {"REGISTER", "UNDO"}
bl_idname = "mesh.primitive_torusknot_add"
bl_label = "Add Torus Knot"
bl_description = "Construct a torus knot mesh"
bl_options = {"REGISTER", "UNDO"}
resolution = bpy.props.IntProperty(name="Resolution",
description="Resolution of the Torus Knot",
default=80, min=30, max=256)
resolution = IntProperty(
name="Resolution",
description="Resolution of the Torus Knot",
default=80,
min=30, max=256
)
objecttype = IntProperty(
name="Knot Type",
description="Type of Knot",
default=1,
min=1, max=3
)
objecttype = bpy.props.IntProperty(name="Knot Type",
description="Type of Knot",
default=1, min=1, max=3)
def execute(self, context):
verts, faces = make_knot(self.objecttype, self.resolution)
obj = create_mesh_object(context, verts, [], faces, "Torus Knot")
def execute(self, context):
verts, faces = make_knot(self.objecttype,
self.resolution)
obj = create_mesh_object(context, verts, [], faces, "Torus Knot")
return {'FINISHED'}
return {'FINISHED'}

View File

@ -1,30 +1,36 @@
# GPL # by Paulo_Gomes
# GPL # "author": Paulo_Gomes
import bpy
from bpy.props import *
from mathutils import *
from mathutils import Quaternion, Vector
from math import cos, sin, pi
from bpy.props import (
FloatProperty,
IntProperty,
BoolProperty,
)
# Create a new mesh (object) from verts/edges/faces.
# 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).
# 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.
# Make a mesh from a list of verts/edges/faces
mesh.from_pydata(verts, edges, faces)
# Update mesh geometry after adding stuff.
# 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.
# A very simple "bridge" tool
def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False):
faces = []
@ -45,7 +51,7 @@ def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False):
total = len(vertIdx2)
if closed:
# Bridge the start with the end.
# Bridge the start with the end
if flipped:
face = [
vertIdx1[0],
@ -62,7 +68,7 @@ def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False):
face.append(vertIdx2[total - 1])
faces.append(face)
# Bridge the rest of the faces.
# Bridge the rest of the faces
for num in range(total - 1):
if flipped:
if fan:
@ -81,6 +87,7 @@ def createFaces(vertIdx1, vertIdx2, closed=False, flipped=False):
return faces
def add_twisted_torus(major_rad, minor_rad, major_seg, minor_seg, twists):
PI_2 = pi * 2.0
z_axis = (0.0, 0.0, 1.0)
@ -108,7 +115,7 @@ def add_twisted_torus(major_rad, minor_rad, major_seg, minor_seg, twists):
edgeloop.append(len(verts))
verts.append(vec)
# Remember very first edgeloop.
# Remember very first edgeloop
if major_index == 0:
edgeloop_first = edgeloop
@ -125,56 +132,72 @@ def add_twisted_torus(major_rad, minor_rad, major_seg, minor_seg, twists):
return verts, faces
class AddTwistedTorus(bpy.types.Operator):
"""Add a torus mesh"""
bl_idname = "mesh.primitive_twisted_torus_add"
bl_label = "Add Torus"
bl_label = "Add Twisted Torus"
bl_description = "Construct a twisted torus mesh"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
major_radius = FloatProperty(name="Major Radius",
description="Radius from the origin to the" \
" center of the cross section",
major_radius = FloatProperty(
name="Major Radius",
description="Radius from the origin to the"
" center of the cross section",
min=0.01,
max=100.0,
default=1.0)
minor_radius = FloatProperty(name="Minor Radius",
default=1.0
)
minor_radius = FloatProperty(
name="Minor Radius",
description="Radius of the torus' cross section",
min=0.01,
max=100.0,
default=0.25)
major_segments = IntProperty(name="Major Segments",
default=0.25
)
major_segments = IntProperty(
name="Major Segments",
description="Number of segments for the main ring of the torus",
min=3,
max=256,
default=48)
minor_segments = IntProperty(name="Minor Segments",
default=48
)
minor_segments = IntProperty(
name="Minor Segments",
description="Number of segments for the minor ring of the torus",
min=3,
max=256,
default=12)
twists = IntProperty(name="Twists",
default=12
)
twists = IntProperty(
name="Twists",
description="Number of twists of the torus",
min=0,
max=256,
default=1)
use_abso = BoolProperty(name="Use Int/Ext Controls",
default=1
)
use_abso = BoolProperty(
name="Use Int/Ext Controls",
description="Use the Int/Ext controls for torus dimensions",
default=False)
abso_major_rad = FloatProperty(name="Exterior Radius",
default=False
)
abso_major_rad = FloatProperty(
name="Exterior Radius",
description="Total Exterior Radius of the torus",
min=0.01,
max=100.0,
default=1.0)
abso_minor_rad = FloatProperty(name="Inside Radius",
default=1.0
)
abso_minor_rad = FloatProperty(
name="Inside Radius",
description="Total Interior Radius of the torus",
min=0.01,
max=100.0,
default=0.5)
default=0.5
)
def execute(self, context):
if self.use_abso == True:
if self.use_abso is True:
extra_helper = (self.abso_major_rad - self.abso_minor_rad) * 0.5
self.major_radius = self.abso_minor_rad + extra_helper
self.minor_radius = extra_helper
@ -184,9 +207,10 @@ class AddTwistedTorus(bpy.types.Operator):
self.minor_radius,
self.major_segments,
self.minor_segments,
self.twists)
self.twists
)
# Actually create the mesh object from this geometry data.
# Create the mesh object from this geometry data.
obj = create_mesh_object(context, verts, [], faces, "TwistedTorus")
return {'FINISHED'}

View File

@ -1,12 +1,7 @@
# 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
from bpy.types import Operator
def object_origin(width, height, depth):
@ -14,10 +9,7 @@ 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)
]
verts = [(+0.0, +0.0, +0.0)]
faces = []
# apply size
@ -26,42 +18,45 @@ def object_origin(width, height, depth):
return verts, faces
class AddVert(bpy.types.Operator):
'''Add a Single Vertice to Edit Mode'''
class AddVert(Operator):
bl_idname = "mesh.primitive_vert_add"
bl_label = "Single Vert"
bl_description = "Add a Single Vertice to Edit Mode"
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.object.mode_set(mode='EDIT')
return {'FINISHED'}
class AddEmptyVert(bpy.types.Operator):
'''Add an Object Origin to Edit Mode'''
class AddEmptyVert(Operator):
bl_idname = "mesh.primitive_emptyvert_add"
bl_label = "Empty Object Origin"
bl_description = "Add an Object Origin to Edit Mode"
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.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)
bpy.ops.mesh.primitive_plane_add(enter_editmode=True)
sempty = bpy.context.object
sempty.name = "SymmEmpty"
@ -70,16 +65,17 @@ def Add_Symmetrical_Empty():
if (sempty.modifiers and sempty.modifiers['Mirror']):
pass
else:
bpy.ops.object.modifier_add(type ='MIRROR')
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')
bpy.ops.mesh.delete(type='VERT')
def Add_Symmetrical_Vert():
bpy.ops.mesh.primitive_plane_add(enter_editmode = True)
bpy.ops.mesh.primitive_plane_add(enter_editmode=True)
sempty = bpy.context.object
sempty.name = "SymmVert"
@ -88,15 +84,15 @@ def Add_Symmetrical_Vert():
if (sempty.modifiers and sempty.modifiers['Mirror']):
pass
else:
bpy.ops.object.modifier_add(type ='MIRROR')
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):
class AddSymmetricalEmpty(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"
@ -106,7 +102,7 @@ class AddSymmetricalEmpty(bpy.types.Operator):
layout = self.layout
mirror = bpy.context.object.modifiers['Mirror']
layout.prop(mirror,'use_clip', text="Use Clipping")
layout.prop(mirror, "use_clip", text="Use Clipping")
layout.label("Mirror Axis")
row = layout.row(align=True)
@ -116,10 +112,11 @@ class AddSymmetricalEmpty(bpy.types.Operator):
def execute(self, context):
Add_Symmetrical_Empty()
return {'FINISHED'}
class AddSymmetricalVert(bpy.types.Operator):
class AddSymmetricalVert(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"
@ -129,7 +126,7 @@ class AddSymmetricalVert(bpy.types.Operator):
layout = self.layout
mirror = bpy.context.object.modifiers['Mirror']
layout.prop(mirror,'use_clip', text="Use Clipping")
layout.prop(mirror, "use_clip", text="Use Clipping")
layout.label("Mirror Axis")
row = layout.row(align=True)
@ -139,4 +136,5 @@ class AddSymmetricalVert(bpy.types.Operator):
def execute(self, context):
Add_Symmetrical_Vert()
return {'FINISHED'}

View File

@ -38,12 +38,13 @@ else:
import bpy
from bpy.props import *
def register():
bpy.utils.register_module(__name__)
def unregister():
bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()

View File

@ -1,16 +1,18 @@
import bpy
import mathutils
def reset_transform(ob):
m = mathutils.Matrix()
ob.matrix_local = m
def func_add_corrective_pose_shape_fast(source, target):
result = ""
reset_transform(target)
# If target object doesn't have Basis shape key, create it.
try:
num_keys = len( target.data.shape_keys.key_blocks )
num_keys = len(target.data.shape_keys.key_blocks)
except:
basis = target.shape_key_add()
basis.name = "Basis"
@ -21,11 +23,11 @@ def func_add_corrective_pose_shape_fast(source, target):
new_shapekey = target.shape_key_add()
new_shapekey.name = "Shape_" + source.name
new_shapekey_name = new_shapekey.name
key_index = len(target.data.shape_keys.key_blocks)-1
key_index = len(target.data.shape_keys.key_blocks) - 1
target.active_shape_key_index = key_index
# else, the active shape will be used (updated)
target.show_only_shape_key = True
shape_key_verts = target.data.shape_keys.key_blocks[ key_index ].data
shape_key_verts = target.data.shape_keys.key_blocks[key_index].data
try:
vgroup = target.active_shape_key.vertex_group
target.active_shape_key.vertex_group = ''
@ -36,20 +38,20 @@ def func_add_corrective_pose_shape_fast(source, target):
# copy the local vertex positions to the new shape
verts = source.data.vertices
try:
for n in range( len(verts)):
for n in range(len(verts)):
shape_key_verts[n].co = verts[n].co
# go to all armature modifies and unpose the shape
# go to all armature modifies and unpose the shape
except:
message = "***ERROR***, meshes have different number of vertices"
result = message
result = message
for n in target.modifiers:
if n.type == 'ARMATURE' and n.show_viewport:
#~ print("got one")
# print("got one")
n.use_bone_envelopes = False
n.use_deform_preserve_volume = False
n.use_vertex_groups = True
armature = n.object
unposeMesh( shape_key_verts, target, armature)
unposeMesh(shape_key_verts, target, armature)
break
# set the new shape key value to 1.0, so we see the result instantly
@ -58,20 +60,21 @@ def func_add_corrective_pose_shape_fast(source, target):
target.active_shape_key.vertex_group = vgroup
except:
print("bluba")
result = result + "bluba"
result = result + "bluba"
pass
target.show_only_shape_key = False
target.data.update()
return result
class add_corrective_pose_shape_fast(bpy.types.Operator):
'''Adds 1st object as shape to 2nd object as pose shape (only 1 armature)'''
bl_idname = "object.add_corrective_pose_shape_fast"
bl_label = "Add object as corrective shape faster"
bl_description = "Adds 1st object as shape to 2nd object as pose shape (only 1 armature)"
@classmethod
def poll(cls, context):
return context.active_object != None
return context.active_object is not None
def execute(self, context):
@ -87,12 +90,15 @@ class add_corrective_pose_shape_fast(bpy.types.Operator):
source = selection[0]
print(source)
print(target)
func_add_corrective_pose_shape_fast( source, target)
func_add_corrective_pose_shape_fast(source, target)
return {'FINISHED'}
def register():
bpy.utils.register_module(__name__)
def unregister():
bpy.utils.unregister_module(__name__)

View File

@ -1,8 +1,9 @@
import math
from math import sin, cos
from math import sin, cos, sqrt
from .vefm_271 import *
class form(mesh):
def __init__(self, uresolution, vresolution, uscale, vscale, upart,\
def __init__(self, uresolution, vresolution, uscale, vscale, upart,
vpart, uphase, vphase, utwist, vtwist, xscale, yscale, sform):
mesh.__init__(self)
@ -24,11 +25,11 @@ class form(mesh):
self.yscale = yscale
self.sform = sform
if self.upart != 1.0: ## there is a gap in the major radius
if self.upart != 1.0: # there is a gap in the major radius
self.uflag = 1
else:
self.uflag = 0
if self.vpart != 1.0: ## there is a gap in the minor radius
if self.vpart != 1.0: # there is a gap in the minor radius
self.vflag = 1
else:
self.vflag = 0
@ -50,25 +51,25 @@ class form(mesh):
self.yscaleflag = 1
else:
self.yscaleflag = 0
self.rowlist=[]
self.rowlist = []
def generatepoints(self):
for i in range(self.ufinish):
row=[]
row = []
for j in range(self.vfinish):
u = self.ustep * i + self.uphase
v = self.vstep * j + self.vphase
if self.sform[12]:
r1 = self.superform(self.sform[0], self.sform[1], self.sform[2],\
self.sform[3], self.sform[14] + u, self.sform[4],\
self.sform[5], self.sform[16] * v)
r1 = self.superform(self.sform[0], self.sform[1], self.sform[2],
self.sform[3], self.sform[14] + u, self.sform[4],
self.sform[5], self.sform[16] * v)
else:
r1 = 1.0
if self.sform[13]:
r2 = self.superform(self.sform[6], self.sform[7], self.sform[8],\
self.sform[9], self.sform[15] + v, self.sform[10],\
self.sform[11], self.sform[17] * v)
r2 = self.superform(self.sform[6], self.sform[7], self.sform[8],
self.sform[9], self.sform[15] + v, self.sform[10],
self.sform[11], self.sform[17] * v)
else:
r2 = 1.0
x, y, z = self.formula(u, v, r1, r2)
@ -82,7 +83,7 @@ class form(mesh):
else:
for i in range(len(self.rowlist)):
self.rowlist[i].append(self.rowlist[i][0])
if self.uflag:
if self.uflag:
pass
else:
self.rowlist.append(self.rowlist[0])
@ -113,17 +114,19 @@ class form(mesh):
edge4 = edge(b, c)
self.edges.append(edge4)
class grid(form):
def __init__(self, uresolution, vresolution, uscale, vscale, upart, vpart,\
def __init__(self, uresolution, vresolution, uscale, vscale, upart, vpart,
uphase, vphase, utwist, vtwist, xscale, yscale, sform):
form.__init__(self, uresolution, vresolution, uscale, vscale, upart, vpart,\
uphase, vphase, utwist, vtwist, xscale, yscale, sform)
form.__init__(self, uresolution, vresolution, uscale, vscale, upart, vpart,
uphase, vphase, utwist, vtwist, xscale, yscale, sform)
unit = 1.0 / self.a360
if self.ures == 1 :
print("\n***ERRORin forms_271.grid L121***, ures is 1, changed into 2\n\n")
if self.ures == 1:
print("\n***ERRORin forms_271.grid L126***, ures is 1, changed into 2\n\n")
self.ures = 2
if self.vres == 1 :
print("\n***ERROR in grid forms_271.grid L124***, vres is 1, changed into 2\n\n")
if self.vres == 1:
print("\n***ERROR in grid forms_271.grid L129***, vres is 1, changed into 2\n\n")
self.vres = 2
self.ustep = self.a360 / (self.ures - 1)
self.vstep = self.a360 / (self.vres - 1)
@ -152,9 +155,9 @@ class grid(form):
class cylinder(form):
def __init__(self, uresolution, vresolution, uscale, vscale, upart, vpart,\
def __init__(self, uresolution, vresolution, uscale, vscale, upart, vpart,
uphase, vphase, utwist, vtwist, xscale, yscale, sform):
form.__init__(self, uresolution, vresolution, uscale, vscale, upart, vpart,\
form.__init__(self, uresolution, vresolution, uscale, vscale, upart, vpart,
uphase, vphase, utwist, vtwist, xscale, yscale, sform)
unit = 1.0 / self.a360
self.vshift = self.vscale * 0.5
@ -172,10 +175,11 @@ class cylinder(form):
z = v * self.vexpand - self.vshift
return x, y, z
class parabola(form):
def __init__(self, uresolution, vresolution, uscale, vscale, upart, vpart,\
def __init__(self, uresolution, vresolution, uscale, vscale, upart, vpart,
uphase, vphase, utwist, vtwist, xscale, yscale, sform):
form.__init__(self, uresolution, vresolution, uscale, vscale, upart, vpart,\
form.__init__(self, uresolution, vresolution, uscale, vscale, upart, vpart,
uphase, vphase, utwist, vtwist, xscale, yscale, sform)
unit = 1.0 / self.a360
self.vshift = self.vscale * 0.5
@ -194,10 +198,11 @@ class parabola(form):
z = - v * self.vexpand + self.vshift
return x, y, z
class torus(form):
def __init__(self, uresolution, vresolution, uscale, vscale, upart, vpart,\
def __init__(self, uresolution, vresolution, uscale, vscale, upart, vpart,
uphase, vphase, utwist, vtwist, xscale, yscale, sform):
form.__init__(self, uresolution, vresolution, uscale, vscale, upart, vpart,\
form.__init__(self, uresolution, vresolution, uscale, vscale, upart, vpart,
uphase, vphase, utwist, vtwist, xscale, yscale, sform)
self.generatepoints()
self.generatefaces()
@ -211,11 +216,12 @@ class torus(form):
x = (self.vscale + self.uscale * cos(v)) * sin(u) * r1 * r2 * self.xscale
return x, y, z
class sphere(form):
def __init__(self, uresolution, vresolution, uscale, vscale, upart, vpart,\
def __init__(self, uresolution, vresolution, uscale, vscale, upart, vpart,
uphase, vphase, utwist, vtwist, xscale, yscale, sform):
form.__init__(self, uresolution, vresolution, uscale, vscale, upart, vpart,\
uphase,vphase,utwist,vtwist,xscale,yscale,sform)
form.__init__(self, uresolution, vresolution, uscale, vscale, upart, vpart,
uphase, vphase, utwist, vtwist, xscale, yscale, sform)
self.vstep = (self.a360 / (self.vres - 1)) * self.vpart
self.vflag = 1
self.generatepoints()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff