// Last edited on 2022-04-17 22:38:04 by stolfi #macro holder( N, holder_dim, hole_d, hole_x, hole_dy, holder_base_ewd, base_thk, bot_thk, top_thk, side_thk, sep_thk, cup_dp ) // Test tube holder for {N} tubes. // Origin is at front left bottom corner. // Width is along {Y}, height is along {Z}, back is {X=0}. // {holder_dim} overall dimension vector of holder. // {hole_d} diameter of holes. // {hole_x} {X} distance of hole center from back plane. // {hole_dy} {Y} distance between hole centers. // {holder_base_ewd} extra width of base plate on both sides. // {base_thk} thickness of base plate. // {bot_thk} thickness of bottom holding plate. // {top_thk} thickness of top plate. // {side_thk} thickness of side plates. // {sep_thk} thickness of separator plates. // {cup_dp} depth of indentations on bot plate. // Assumes globally defined textures {tx_plate_x,tx_plate_y,tx_plate_z,tx_cup} // Materials: "psai.o" = PSAI (high impact polystyrene) white opaque, "ps.d" = PS (polystyrene) white diffusing. #debug concat("!! holder_dim = < ", str(holder_dim.x,0,3), " ", str(holder_dim.y,0,3), " ", str(holder_dim.z,0,3), " >\n") #local back_thk = 1.7; // Thickness of back plate. #local sex = 2*holder_dim.x; // Reference displacement for exploded view. // Left side plate, with bottom left back corner at origin: #local side_sx = hole_x + hole_d/2 - back_thk; // {X} size of side plates. #local side_sz = holder_dim.z - top_thk; // Height of side plates. #local side_plate = box{ < 0, 0, 0 > + eps3, < side_sx, side_thk, side_sz, > - eps3 texture{ tx_plate_y } } write_pieces( "psai.o", "HSid", 2, side_sz, side_sx, side_thk, "holder side wall" ) #local hole0_y = (holder_dim.y - (N-1)*hole_dy)/2; // {Y} of center of first hole, rel to left plane of holder. // Top plate, with bottom left back corner at origin: #local top_sx = holder_dim.x; // {X} size of top plate. #local top_sy = holder_dim.y; // {Y} size of top plate. #local top_plate = difference{ box{ < 0, 0, 0 > + eps3, < top_sx, top_sy, top_thk > - eps3 } #local hk = 0; #local hx = hole_x; #local hy = hole0_y; #while (hk < N) cylinder{ < 0, 0, 0 - eps >, < 0, 0, top_thk + eps >, hole_d/2 + eps translate < hx, hy, 0 > } #local hy = hy + hole_dy; #local hk = hk + 1; #end texture{ tx_plate_z } } write_pieces( "psai.o", "HTop", 1, top_sy, top_sx, top_thk, "holder top plate" ) // Separator plate, with bottom left back corner at origin: #local sep_sx = hole_x + hole_d/2 - back_thk; // {X} width of separator plates. #local sep_sz = holder_dim.z - top_thk - 2*bot_thk; // Height of separator plates. #local sep_plate = box{ <0,0,0> + eps3, < sep_sx, sep_thk, sep_sz > - eps3 texture{ tx_plate_y } } write_pieces( "psai.o", "HSep", N-1, sep_sz, sep_sx, sep_thk, "separator" ) // Back plate, with bottom left back corner at origin: #local back_sy = holder_dim.y; // {Y} width of back plates. #local back_sz = holder_dim.z - top_thk - base_thk; // Height of back plate. #local back_plate = box{ <0,0,0> + eps3, < back_thk, back_sy, back_sz > - eps3 texture{ tx_plate_x } } write_pieces( "ps.d", "HBak", 1, back_sy, back_sz, back_thk, "holder back wall" ) // Base plate, with bottom left back corner at origin: #local base_sx = holder_dim.x + 2*holder_base_ewd; // {X} size of bot plate. #local base_sy = holder_dim.y; // {Y} size of bot plate. #local base_plate_indent = box{ < 0, 0, 0> - eps3, < side_sx, side_thk, base_thk + bot_thk > + eps3 } #local base_plate_indents = union{ object{ base_plate_indent } object{ base_plate_indent scale < +1, -1, +1 > translate holder_dim.y*y } } #local base_plate = difference{ box{ < 0, 0, 0 > + eps3, < base_sx, base_sy, base_thk > - eps3 } object{ base_plate_indents translate (holder_base_ewd + back_thk)*x } texture{ tx_plate_z } } write_pieces( "psai.o", "HBas", 1, base_sy, base_sx, base_thk, "holder base plate" ) // Bottom plate, with bottom left back corner at origin: #local bot_sx = top_sx - back_thk; // {X} size of bot plate. #local bot_sy = holder_dim.y; // {Y} size of bot plate. #local bot_plate = difference{ box{ < 0, 0, 0 > + eps3, < bot_sx, bot_sy, bot_thk > - eps3 texture{ tx_plate_z } } object{ base_plate_indents translate < 0, 0, -base_thk > } #local hk = 0; #local hx = hole_x - back_thk; #local hy = hole0_y; #while (hk < N) sphere{ < 0, 0, bot_thk + hole_d/2 - cup_dp >, hole_d/2 + eps translate < hx, hy, 0 > texture{ tx_cup } } #local hy = hy + hole_dy; #local hk = hk + 1; #end } write_pieces( "psai.o", "HBot", 1, bot_sy, bot_sx, bot_thk, "holder bottom plate" ) // All together: union{ object{ base_plate translate < -holder_base_ewd, 0, 0 > } object{ bot_plate translate < back_thk, 0, base_thk > translate xplode*sex*< 0, 0, +1 > } object{ top_plate translate < 0, 0, holder_dim.z - top_thk > translate xplode*sex*<0, 0, +3 > } object{ back_plate translate < 0, 0, base_thk > translate xplode*sex*< -1, 0, +2 > } union{ object{ side_plate translate xplode*sex*< 0, -1, +2 > } object{ side_plate scale < +1, -1, +1 > translate holder_dim.y*y translate xplode*sex*< 0, +1, +2 > } union{ #local sep_k = 0; #local sep_x = back_thk; #local sep_y = hole0_y + hole_dy/2 - sep_thk/2; #local sep_z = base_thk + bot_thk; #while (sep_k < N-1) object{ sep_plate translate < sep_x, sep_y, sep_z > } #local sep_y = sep_y + hole_dy; #local sep_k = sep_k + 1; #end translate xplode*sex*< 0, 0, +2 > } translate back_thk*x } } #end