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:
parent
c95e86bcef
commit
c86080a455
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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__)
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
||||
|
|
|
@ -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'}
|
||||
|
||||
|
|
|
@ -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'}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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'}
|
||||
|
|
|
@ -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'}
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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'}
|
||||
|
|
|
@ -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 ===
|
||||
# =================================
|
||||
|
|
|
@ -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'}
|
||||
|
|
|
@ -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'}
|
||||
|
|
|
@ -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'}
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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__)
|
||||
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue