Files
rhinelab-ui/art/shell_reference_details.py

64 lines
4.0 KiB
Python

# Reference face: x=24..1021, y=6..667. Shared by both Blender exports.
# The engraved frame is below the cover, so the moving frost masks every route.
engraving=material('Case_Engraving',(.57,.54,.50),.39,.12)
lip=material('Case_Engraving_Highlight',(.90,.87,.83),.25,.16)
inlay=material('Index_Inlay',(.67,.53,.40),.52,.04)
def case_point(px,py):return ((px-24)/997*5-2.5,(667-py)/661*3.7)
def route(name,pixels):
points=[case_point(x,y) for x,y in pixels]
channel('Case engraved '+name,points,-.075,.0045,engraving)
channel('Case pressed lip '+name,[(x+.007,z-.009) for x,z in points],-.079,.004,lip)
# The top patch finishes at the case's top and front planes: no raised block.
x,z=case_point(92,26)
cut=cube('Temporary inlay recess',(x,-.100,z),(.25,.030,2*(3.7-z)+.002),core,0)
bpy.context.view_layer.objects.active=front_cover
mod=front_cover.modifiers.new('Flush index pocket','BOOLEAN');mod.operation='DIFFERENCE';mod.object=cut
bpy.ops.object.modifier_apply(modifier=mod.name);bpy.data.objects.remove(cut,do_unlink=True)
cube('Index flush inlay',(x,-.102,z),(.25,.002,2*(3.7-z)),inlay,.0008)
route('outer upper left',[(974,14),(35,14),(35,612)])
route('outer lower right',[(1011,64),(1011,655),(80,655)])
route('upper circuit',[(35,171),(54,171),(78,143),(78,76),(98,57),(172,57),
(191,46),(383,46),(405,57),(598,57),(617,68),(650,68),(655,64),(650,57),
(620,57),(605,44),(600,43),(596,47),(597,54),(614,67),(760,67),
(779,53),(782,47),(778,43),(773,44),(757,57),(722,57),(719,61),(720,68),
(763,68),(780,57),(894,57),(917,40),(973,40)])
route('left hook',[(68,47),(51,64),(51,105),(53,111),(60,113),(64,109),
(64,70),(90,42),(128,42),(134,39),(135,34),(131,28),(119,28)])
route('inner frame',[(115,565),(115,84),(132,67),(948,67),(968,85),(968,162),
(981,192),(981,550),(909,622),(131,622),(118,609),(118,590)])
route('lower return',[(128,629),(911,629),(985,556)])
route('bottom catch',[(793,652),(798,648),(890,648),(894,653),(1010,653)])
for label,px,py,start,end in [('upper right',999,37,0.30*math.pi,1.84*math.pi),
('lower left',57,642,-.75*math.pi,.78*math.pi)]:
x,z=case_point(px,py)
# C-shaped shallow boss, tied into the pressed frame rather than a raised ring.
for radius in [.104,.127]:
points=[(x+radius*math.cos(start+(end-start)*i/64),
z+radius*math.sin(start+(end-start)*i/64)) for i in range(65)]
channel('Case engraved screw boss '+label,points,-.076,.0045,engraving)
channel('Case pressed screw boss '+label,[(a+.006,b-.008) for a,b in points],-.080,.004,lip)
# A real opening leaves the flush metal head readable under a frosted cover.
bpy.ops.mesh.primitive_cylinder_add(vertices=64,radius=.082,depth=.06,
location=(x,-.095,z),rotation=(math.pi/2,0,0))
cut=bpy.context.object
bpy.context.view_layer.objects.active=front_cover
mod=front_cover.modifiers.new('Flush fastener opening','BOOLEAN');mod.operation='DIFFERENCE';mod.object=cut
bpy.ops.object.modifier_apply(modifier=mod.name);bpy.data.objects.remove(cut,do_unlink=True)
annular_profile('Countersunk washer '+label,x,z,
[(.061,-.094),(.080,-.094),(.080,-.100),(.071,-.103),(.063,-.103),(.061,-.099)],lip,64)
bpy.ops.mesh.primitive_cylinder_add(vertices=48,radius=.060,depth=.010,
location=(x,-.098,z),rotation=(math.pi/2,0,0))
head=bpy.context.object;head.name='Machined screw '+label;head.data.materials.append(metal)
mod=head.modifiers.new('Head chamfer','BEVEL');mod.width=.003;mod.segments=3
bpy.ops.object.modifier_apply(modifier=mod.name)
for angle in [-.22,math.pi/2-.22]:
cut=cube('Temporary drive cutter',(x,-.103,z),(.069,.008,.014),core,.001)
cut.rotation_euler.y=angle
bpy.context.view_layer.objects.active=head
mod=head.modifiers.new('Cross recessed drive','BOOLEAN');mod.operation='DIFFERENCE';mod.object=cut
bpy.ops.object.modifier_apply(modifier=mod.name);bpy.data.objects.remove(cut,do_unlink=True)
head.modifiers.new('Fastener normals','WEIGHTED_NORMAL')