diff --git a/spoolstore/poc.py b/spoolstore/poc.py index 6004114..42284f4 100644 --- a/spoolstore/poc.py +++ b/spoolstore/poc.py @@ -1,119 +1,158 @@ """Proof of concept models for SpoolStore.""" +from math import cos, radians, sin + import solid2 as sp from libdsps.grids import hex_grid from libdsps.shapes import rect_frame -DRAWER_INNER_WIDTH = 220 -DRAWER_INNER_LENGTH = 270 -DRAWER_INNER_FLOOR_THICKNESS = 3 -DRAWER_INNER_DEPTH = 75 +DRAWER_INNER_WIDTH = 75 +DRAWER_INNER_LENGTH = 240 +DRAWER_INNER_DEPTH = 220 SPOOL_OUTER_D = 200 SPOOL_INNER_D = 55 - -SPOOLPIN_FRONT_OFFSET = 110 -SPOOLPIN_D = SPOOL_INNER_D - 10 -SPOOLPIN_HEIGHT = 20 -SPOOLPIN_RAISE = 5 - -SPLITTER_THICKNESS = 3 -SPLITTER_FRONT_OFFSET = 220 +SPOOL_WIDTH = 67 +SPOOL_SIDE_THICK = 3.5 LID_THICKNESS = 3 SIDE_THICKNESS = 3 +FLOOR_THICKNESS = 3 +BACK_THICKNESS = 3 + +RAIL_RADIUS = 3 +RAIL_FRONT_ANGLE = 20 +RAIL_BACK_ANGLE = -40 +RAIL_SUPPORT_THICKNESS = 4 +RAIL_SUPPORT_EXTRA_RADIUS = 1 +RAIL_SUPPORT_SIDE_MARGIN = 2 +RAIL_WIDTH_MARGIN = 3 +RAIL_SPOOL_HEIGHT = 5 +RAIL_SPOOL_FRONT_DIST = 5 +RAIL_PARKED_SPOOL = True +RAIL_CRITICAL_SPOOL = True + +DRAWER_OUTER_WIDTH = DRAWER_INNER_WIDTH + SIDE_THICKNESS * 2 +DRAWER_OUTER_LENGTH = DRAWER_INNER_LENGTH + LID_THICKNESS + BACK_THICKNESS FRAME_MARGIN = 8 GRID_STRIDE = 38 GRID_FILL_RATIO = 0.08 -XX = 2 +XX = .1 -def _gen_hex_frame( +def _gen_hex_frame( # noqa: PLR0913 width: float, length: float, height: float, frame_size: float, stride: float, fill_ratio: float ) -> sp.OpenSCADObjectPlus: frame = rect_frame(width, length, height, frame_size) grid = hex_grid(width - frame_size * 2, length - frame_size * 2, height, stride, fill_ratio) - hex_frame = sp.union()(frame, grid) - return hex_frame + return sp.union()(frame, grid) -def _gen_spool_holder() -> sp.OpenSCADObjectPlus: - spool_raise = sp.cylinder(d=SPOOL_OUTER_D, h=SPOOLPIN_RAISE, center=False) - pin = sp.cylinder(d=SPOOLPIN_D, h=SPOOLPIN_HEIGHT, center=False) - pin = sp.up(SPOOLPIN_RAISE)(pin) - spool_holder = sp.union()(pin, spool_raise) - spool_holder = sp.color((0.75, 0.5, 0.5))(spool_holder) - return spool_holder +def _gen_spool(color: sp.Vec3 = (0, 1, 0), alpha: float = .3) -> sp.OpenSCADObjectPlus: + side = sp.cylinder(h=SPOOL_SIDE_THICK, d=SPOOL_OUTER_D, _fn=36, center=True) + side = sp.rotateY(90)(side) + left = sp.left(SPOOL_WIDTH / 2 - SPOOL_SIDE_THICK/2)(side) + right = sp.right(SPOOL_WIDTH / 2 - SPOOL_SIDE_THICK/2)(side) -def _gen_splitter() -> sp.OpenSCADObjectPlus: - splitter = sp.cube([DRAWER_INNER_WIDTH - SIDE_THICKNESS * 2, SPLITTER_THICKNESS, DRAWER_INNER_DEPTH], center=True) - splitter = sp.up(DRAWER_INNER_DEPTH / 2)(splitter) + core = sp.cylinder(h=SPOOL_WIDTH - SPOOL_SIDE_THICK * 2, d=SPOOL_INNER_D, center=True) + core = sp.rotateY(90)(core) - mask = sp.cube( - [ - DRAWER_INNER_WIDTH - SIDE_THICKNESS * 2 - FRAME_MARGIN * 2, - SPLITTER_THICKNESS + XX, - DRAWER_INNER_DEPTH - FRAME_MARGIN + XX, - ], - center=True, - ) - mask = sp.up((DRAWER_INNER_DEPTH + FRAME_MARGIN + XX) / 2)(mask) - splitter = splitter - mask - - splitter = sp.color((0.5, 0.75, 0.5))(splitter) - return splitter - - -def _gen_top() -> sp.OpenSCADObjectPlus: - lid = _gen_hex_frame( - DRAWER_INNER_WIDTH, SPLITTER_FRONT_OFFSET, LID_THICKNESS, FRAME_MARGIN, GRID_STRIDE, GRID_FILL_RATIO - ) - lid = sp.forward(DRAWER_INNER_LENGTH / 2 - SPOOLPIN_FRONT_OFFSET)(lid) - - frame = rect_frame(DRAWER_INNER_WIDTH, DRAWER_INNER_LENGTH - SPLITTER_FRONT_OFFSET, LID_THICKNESS, FRAME_MARGIN) - frame = sp.forward(-SPLITTER_FRONT_OFFSET / 2)(frame) - frame = sp.color((0.2, 0.2, 0.2))(frame) - - top = sp.union()(frame, lid) - return top + spool = sp.union()(left, right, core) + spool = sp.up(SPOOL_OUTER_D / 2)(spool) + spool = sp.color(color, alpha)(spool) + return spool def _gen_side() -> sp.OpenSCADObjectPlus: - return _gen_hex_frame( + face = _gen_hex_frame( DRAWER_INNER_DEPTH, DRAWER_INNER_LENGTH, SIDE_THICKNESS, FRAME_MARGIN, GRID_STRIDE, GRID_FILL_RATIO ) + return face -#def _gen_back() + +def _gen_bottom() -> sp.OpenSCADObjectPlus: + floor = sp.cube([DRAWER_OUTER_WIDTH, DRAWER_OUTER_LENGTH, FLOOR_THICKNESS], center=True) + floor = sp.up(FLOOR_THICKNESS / 2)(floor) + return floor + + +def _gen_rail() -> sp.OpenSCADObjectPlus: + rail = sp.cylinder(h=DRAWER_INNER_WIDTH - RAIL_WIDTH_MARGIN*2, r=RAIL_RADIUS, _fn=12, center=True) + rail = sp.rotateY(90)(rail) + return rail + + +def _gen_spool_rails() -> sp.OpenSCADObjectPlus: + parked_spool = _gen_spool() + parked_spool = sp.up(RAIL_SPOOL_HEIGHT)(parked_spool) + + rail_pos_radius = SPOOL_OUTER_D / 2 + RAIL_RADIUS + f_y_off = sin(radians(RAIL_FRONT_ANGLE)) * rail_pos_radius + f_z_off = (1-cos(radians(RAIL_FRONT_ANGLE))) * rail_pos_radius - RAIL_RADIUS + RAIL_SPOOL_HEIGHT + b_y_off = sin(radians(RAIL_BACK_ANGLE)) * rail_pos_radius + b_z_off = (1-cos(radians(RAIL_BACK_ANGLE))) * rail_pos_radius - RAIL_RADIUS + RAIL_SPOOL_HEIGHT + + back_rail = _gen_rail() + back_rail = sp.up(f_z_off)(back_rail) + back_rail = sp.forward(f_y_off)(back_rail) + + front_rail = _gen_rail() + front_rail = sp.up(b_z_off)(front_rail) + front_rail = sp.forward(b_y_off)(front_rail) + + rail_base = sp.cylinder(h=RAIL_SUPPORT_THICKNESS, r=RAIL_RADIUS+RAIL_SUPPORT_EXTRA_RADIUS, center=True) + rail_base = sp.rotateY(90)(rail_base) + back_rail_base = sp.up(b_z_off)(rail_base) + back_rail_base = sp.forward(b_y_off)(back_rail_base) + front_rail_base = sp.up(f_z_off)(rail_base) + front_rail_base = sp.forward(f_y_off)(front_rail_base) + #TODO: Mid rail to reduce overlap with spool contents + back_base = sp.forward(b_y_off)(sp.cube([RAIL_SUPPORT_THICKNESS, RAIL_RADIUS*2, 1], center=True)) + front_base = sp.forward(f_y_off)(sp.cube([RAIL_SUPPORT_THICKNESS, RAIL_RADIUS*2, 1], center=True)) + back_support = sp.hull()(back_rail_base, back_base) + front_support = sp.hull()(front_rail_base, front_base) + inter_support = sp.hull()(front_rail_base, back_rail_base) + rail_support = sp.union()(back_support, front_support, inter_support) + + support_offset = SPOOL_WIDTH/2 - SPOOL_SIDE_THICK - RAIL_SUPPORT_THICKNESS/2 - RAIL_SUPPORT_SIDE_MARGIN + left_support = sp.left(support_offset)(rail_support) + right_support = sp.right(support_offset)(rail_support) + rail_supports = sp.union()(left_support, right_support) + + critical_spool = _gen_spool((1, 0, 0), 0.3) + critical_spool = sp.up(f_z_off + RAIL_RADIUS)(critical_spool) + critical_spool = sp.forward(f_y_off)(critical_spool) + critical_spool = sp.right(XX)(critical_spool) + + final = sp.union()(back_rail, front_rail, rail_supports) + if RAIL_PARKED_SPOOL: + final = sp.union()(final, parked_spool) + if RAIL_CRITICAL_SPOOL: + final = sp.union()(final, critical_spool) + final = sp.forward(DRAWER_INNER_LENGTH/2 - SPOOL_OUTER_D/2 - RAIL_SPOOL_FRONT_DIST)(final) + return final def gen_drawer() -> sp.OpenSCADObjectPlus: - inner_floor = sp.cube([DRAWER_INNER_WIDTH, DRAWER_INNER_LENGTH, DRAWER_INNER_FLOOR_THICKNESS], center=True) - inner_floor = sp.up(DRAWER_INNER_FLOOR_THICKNESS / 2)(inner_floor) - - spool_holder = _gen_spool_holder() - spool_holder = sp.forward(DRAWER_INNER_LENGTH / 2 - SPOOLPIN_FRONT_OFFSET)(spool_holder) - - splitter = _gen_splitter() - splitter = sp.forward(DRAWER_INNER_LENGTH / 2 - SPLITTER_FRONT_OFFSET)(splitter) - - top = _gen_top() - top = sp.up(DRAWER_INNER_DEPTH)(top) - left = _gen_side() - left = sp.rotateY(90)(left) + left = sp.rotateY(-90)(left) + left = sp.left(DRAWER_INNER_WIDTH / 2)(left) left = sp.up(DRAWER_INNER_DEPTH / 2)(left) - left = sp.left(-DRAWER_INNER_WIDTH / 2 + SIDE_THICKNESS)(left) right = _gen_side() - right = sp.rotateY(-90)(right) + right = sp.rotateY(90)(right) + right = sp.right(DRAWER_INNER_WIDTH / 2)(right) right = sp.up(DRAWER_INNER_DEPTH / 2)(right) - right = sp.right(-DRAWER_INNER_WIDTH / 2 + SIDE_THICKNESS)(right) - drawer = sp.up(DRAWER_INNER_FLOOR_THICKNESS)( - sp.union()(sp.down(DRAWER_INNER_FLOOR_THICKNESS)(inner_floor), spool_holder, splitter, top, left, right) - ) + bottom = _gen_bottom() + bottom = sp.down(FLOOR_THICKNESS)(bottom) + bottom = sp.color((0.2, 0.2, 0.2))(bottom) - return drawer + rails = _gen_spool_rails() + + final = sp.union()(left, right, bottom, rails) + final = sp.up(FLOOR_THICKNESS)(final) + return final