254 lines
9.2 KiB
Python
254 lines
9.2 KiB
Python
import bpy
|
|
from mathutils import Vector, Euler
|
|
import bmesh
|
|
import math
|
|
|
|
def NormalInDirection(normal, direction, limit = 0.99):
|
|
return abs(direction.dot( normal )) > limit
|
|
|
|
def UpOrDown(normal):
|
|
|
|
up = NormalInDirection(normal, Vector((0.0, 0.0, 1.0)), limit = 0.99)
|
|
down = NormalInDirection(normal, Vector((0.0, 0.0, -1.0)), limit = 0.99)
|
|
if up or down:
|
|
return True
|
|
return False
|
|
|
|
def generate_pendant_shade(shape_parameters):
|
|
|
|
radius = shape_parameters["radius"]
|
|
depth = shape_parameters["height"]
|
|
print(depth)
|
|
|
|
bpy.ops.mesh.primitive_cylinder_add(radius=radius,
|
|
depth=depth)
|
|
cone = bpy.data.objects["Cylinder"]
|
|
cone.name = "shade"
|
|
bpy.ops.object.mode_set(mode='EDIT')
|
|
|
|
num_subdivisions = 3
|
|
if len(shape_parameters["division_offsets"])>3:
|
|
num_subdivisions = 4
|
|
for idx in range(num_subdivisions):
|
|
bpy.ops.mesh.subdivide()
|
|
|
|
bm = bmesh.from_edit_mesh(cone.data)
|
|
num_verts = len(bm.verts)
|
|
|
|
summed_offset = 0.0
|
|
for jdx in range(len(shape_parameters["division_offsets"])):
|
|
summed_offset += shape_parameters["division_offsets"][jdx]
|
|
|
|
for idx in range(num_verts):
|
|
bm.verts.ensure_lookup_table()
|
|
vert = bm.verts[idx]
|
|
theta = math.atan2(vert.co.x, vert.co.y)
|
|
vert.co.z = vert.co.z -depth/2.0
|
|
|
|
delta = abs(vert.co.z)
|
|
frac = delta/depth
|
|
|
|
summed_offset = 0.0
|
|
prev_offset = 0.0
|
|
|
|
division_index = len(shape_parameters["division_offsets"])-1
|
|
for jdx in range(len(shape_parameters["division_offsets"])):
|
|
prev_offset = summed_offset
|
|
summed_offset += shape_parameters["division_offsets"][jdx]
|
|
if frac >=prev_offset and frac <= summed_offset:
|
|
division_index = jdx
|
|
current_offset = shape_parameters["division_offsets"][division_index]
|
|
division_type = shape_parameters["division_patterns"][division_index]
|
|
|
|
if division_index==0:
|
|
division_radius = shape_parameters["fixture_radius"]
|
|
previous_offset = 0.0
|
|
previous_radius = division_radius
|
|
else:
|
|
division_radius = shape_parameters["radius"]*shape_parameters["division_radii"][division_index]
|
|
previous_offset = shape_parameters["division_offsets"][division_index-1]
|
|
previous_radius = shape_parameters["radius"]*shape_parameters["division_radii"][division_index-1]
|
|
if previous_radius< shape_parameters["fixture_radius"]:
|
|
previous_radius = shape_parameters["fixture_radius"]
|
|
|
|
if division_radius<previous_radius:
|
|
division_radius = previous_radius
|
|
|
|
if division_type == "square":
|
|
mapped_rad = division_radius + (frac)**2
|
|
vert.co.x = mapped_rad*math.sin(theta)
|
|
vert.co.y = mapped_rad*math.cos(theta)
|
|
elif division_type == "sine":
|
|
mapped_rad = division_radius + math.sin(math.pi/2.0*frac)
|
|
vert.co.x = mapped_rad*math.sin(theta)
|
|
vert.co.y = mapped_rad*math.cos(theta)
|
|
elif division_type == "ramp":
|
|
mapped_rad = division_radius + frac
|
|
vert.co.x = mapped_rad*math.sin(theta)
|
|
vert.co.y = mapped_rad*math.cos(theta)
|
|
elif division_type == "inv_ramp":
|
|
mapped_rad = division_radius + frac
|
|
vert.co.x = mapped_rad*math.sin(theta)
|
|
vert.co.y = mapped_rad*math.cos(theta)
|
|
else: #straight
|
|
vert.co.x = division_radius*math.sin(theta)
|
|
vert.co.y = division_radius*math.cos(theta)
|
|
|
|
for face in bm.faces:
|
|
if UpOrDown(face.normal):
|
|
face.select = True
|
|
else:
|
|
face.select = False
|
|
faces_select = [f for f in bm.faces if f.select]
|
|
bmesh.ops.delete(bm, geom=faces_select, context=3)
|
|
bmesh.update_edit_mesh(cone.data, True)
|
|
|
|
# Extrude faces
|
|
bpy.ops.mesh.select_mode( type = 'FACE' )
|
|
bpy.ops.mesh.select_all( action = 'SELECT' )
|
|
bpy.ops.mesh.extrude_region_move(
|
|
TRANSFORM_OT_translate={"value":(0, 0, 0.01)} )
|
|
bpy.ops.mesh.extrude_region_shrink_fatten(
|
|
TRANSFORM_OT_shrink_fatten={"value":-0.05})
|
|
bpy.ops.object.mode_set(mode='OBJECT')
|
|
return cone
|
|
|
|
def generate_cone_shade(radius1, radius2, depth):
|
|
|
|
bpy.ops.mesh.primitive_cone_add(radius1=radius1,
|
|
radius2=radius2,
|
|
depth=depth)
|
|
cone = bpy.data.objects["Cone"]
|
|
cone.name = "shade"
|
|
bpy.ops.object.mode_set(mode='EDIT')
|
|
bm = bmesh.from_edit_mesh(cone.data)
|
|
for face in bm.faces:
|
|
if UpOrDown(face.normal):
|
|
face.select = True
|
|
else:
|
|
face.select = False
|
|
faces_select = [f for f in bm.faces if f.select]
|
|
bmesh.ops.delete(bm, geom=faces_select, context=3)
|
|
bmesh.update_edit_mesh(cone.data, True)
|
|
|
|
# Extrude faces
|
|
bpy.ops.mesh.select_mode( type = 'FACE' )
|
|
bpy.ops.mesh.select_all( action = 'SELECT' )
|
|
bpy.ops.mesh.extrude_region_move(
|
|
TRANSFORM_OT_translate={"value":(0, 0, 0.01)} )
|
|
bpy.ops.mesh.extrude_region_shrink_fatten(
|
|
TRANSFORM_OT_shrink_fatten={"value":-0.05})
|
|
bpy.ops.object.mode_set(mode='OBJECT')
|
|
return cone
|
|
|
|
def generate_mesh_shade(radius1, radius2, depth):
|
|
|
|
bpy.ops.mesh.primitive_cube_add(radius=radius1)
|
|
cube = bpy.data.objects["Cube"]
|
|
cube.name = "shade"
|
|
bpy.ops.object.mode_set(mode='EDIT')
|
|
|
|
for idx in range(3):
|
|
bpy.ops.mesh.subdivide()
|
|
|
|
bm = bmesh.from_edit_mesh(cube.data)
|
|
for i in range( len( bm.verts ) ):
|
|
bm.verts.ensure_lookup_table()
|
|
vert = bm.verts[i]
|
|
#theta = math.atan2(vert.co.x, vert.co.y)
|
|
vert.co.z = vert.co.z - radius1
|
|
vert.co.z = vert.co.z*2.0
|
|
height = radius1*2.0
|
|
vert.co.y = vert.co.y*0.03
|
|
vert.co.x = vert.co.x*0.1 + radius1/2.0
|
|
theta = abs(vert.co.z/height)
|
|
vert.co.x = vert.co.x + 2.0*radius1*math.sin(theta)
|
|
vert.co.z = vert.co.z + 1.0*radius1
|
|
bpy.ops.object.mode_set(mode='OBJECT')
|
|
|
|
num_slats = 36
|
|
cube_copy = cube.data.copy()
|
|
for idx in range(num_slats-1):
|
|
ob = bpy.data.objects.new("Cube Copy"+str(idx), cube_copy)
|
|
angle = 2.0*(math.pi/float(num_slats))*float(idx+1)
|
|
ob.rotation_euler = Euler((0.0, 0.0, angle), 'XYZ')
|
|
scene = bpy.context.scene
|
|
scene.objects.link(ob)
|
|
scene.update()
|
|
|
|
# Add torus
|
|
bpy.ops.mesh.primitive_torus_add(location=(0.0, 0.0, -2.6*radius1),
|
|
major_radius=2.4*radius1,
|
|
minor_radius=0.02)
|
|
|
|
for ob in bpy.context.scene.objects:
|
|
if ob.type == 'MESH':
|
|
ob.select = True
|
|
bpy.context.scene.objects.active = ob
|
|
else:
|
|
ob.select = False
|
|
bpy.ops.object.join()
|
|
|
|
return cube
|
|
|
|
def make_square_ring(radius, depth, thickness):
|
|
|
|
bpy.ops.mesh.primitive_cylinder_add(radius=radius,
|
|
depth=depth)
|
|
cone = bpy.data.objects["Cylinder"]
|
|
cone.name = "square_ring"
|
|
bpy.ops.object.mode_set(mode='EDIT')
|
|
bm = bmesh.from_edit_mesh(cone.data)
|
|
for face in bm.faces:
|
|
if UpOrDown(face.normal):
|
|
face.select = True
|
|
else:
|
|
face.select = False
|
|
faces_select = [f for f in bm.faces if f.select]
|
|
bmesh.ops.delete(bm, geom=faces_select, context=3)
|
|
bmesh.update_edit_mesh(cone.data, True)
|
|
|
|
# Extrude faces
|
|
bpy.ops.mesh.select_mode( type = 'FACE' )
|
|
bpy.ops.mesh.select_all( action = 'SELECT' )
|
|
bpy.ops.mesh.extrude_region_move(
|
|
TRANSFORM_OT_translate={"value":(0, 0, 0.01)} )
|
|
bpy.ops.mesh.extrude_region_shrink_fatten(
|
|
TRANSFORM_OT_shrink_fatten={"value":-thickness})
|
|
bpy.ops.object.mode_set(mode='OBJECT')
|
|
return bpy.data.objects["square_ring"]
|
|
|
|
def generate_led_shade(radius1, radius2, depth):
|
|
|
|
ring1 = make_square_ring(3.0*radius1, depth/10.0, 0.2)
|
|
bpy.ops.transform.rotate(value=-math.pi/12.0, axis=(1.0,0.0,0.0))
|
|
|
|
ring2 = make_square_ring(1.5*radius1, depth/10.0, 0.2)
|
|
bpy.ops.transform.rotate(value=math.pi/12.0, axis=(1.0,0.0,0.0))
|
|
|
|
ring3 = make_square_ring(1.0*radius1, depth/10.0, 0.2)
|
|
bpy.ops.transform.rotate(value=-math.pi/8.0, axis=(1.0,0.0,0.0))
|
|
|
|
for ob in bpy.context.scene.objects:
|
|
if ob.type == 'MESH':
|
|
ob.select = True
|
|
bpy.context.scene.objects.active = ob
|
|
else:
|
|
ob.select = False
|
|
bpy.ops.object.join()
|
|
|
|
bpy.context.scene.objects.active = bpy.data.objects["square_ring"]
|
|
bpy.data.objects["square_ring"].name = "shade"
|
|
|
|
ring1 = make_square_ring(3.0*radius1+0.01, depth/16.0, 0.2)
|
|
bpy.ops.transform.rotate(value=-math.pi/12.0, axis=(1.0,0.0,0.0))
|
|
|
|
ring2 = make_square_ring(1.5*radius1+0.01, depth/16.0, 0.2)
|
|
bpy.ops.transform.rotate(value=math.pi/12.0, axis=(1.0,0.0,0.0))
|
|
|
|
ring3 = make_square_ring(1.1*radius1+0.01, depth/16.0, 0.2)
|
|
bpy.ops.transform.rotate(value=-math.pi/8.0, axis=(1.0,0.0,0.0))
|
|
|
|
return bpy.data.objects["shade"]
|
|
|
|
|