# HG changeset patch # User Paul Boddie # Date 1460303123 -7200 # Node ID 178ff897d32fe3c16c323827adfa12377c0386d4 # Parent f5108ce21563ca270d6fc48986a6529b4fdec7c6 Made modules for the pieces so that they can be checked using a new intersection setting, together with a new setting that "closes" the cartridge. diff -r f5108ce21563 -r 178ff897d32f cartridge.scad --- a/cartridge.scad Sun Apr 10 16:45:18 2016 +0200 +++ b/cartridge.scad Sun Apr 10 17:45:23 2016 +0200 @@ -34,7 +34,7 @@ BACK_CONNECTOR_SECTION = 0; FRONT_LABEL_INSET = 0; TOP_LABEL_INSET = 0; - GROOVE = 0; ROUND_EDGES = 0; ROUND_CONNECTING_EDGES = 0 + GROOVE = 0; ROUND_EDGES = 0; ROUND_CONNECTING_EDGES = 0; Leave all options enabled for more capable 3D printers. */ @@ -78,6 +78,11 @@ APART = 1; PCB = 0; + /* To check overlaps: INTERSECT = 1; CLOSED = 1; */ + + INTERSECT = 0; + CLOSED = 0; + /* To save time (before printing): FILLET = 0; */ FILLET = 1; @@ -587,434 +592,122 @@ /* The actual shapes. */ - front_displacement = APART ? -connector_width * 0.6 : 0; - - if (FRONT) - translate([front_displacement, 0, 0]) - difference() { - - /* The cartridge surfaces. */ - - union() { - - /* Front portion. */ - - if (FRONT_SURFACE) { - - /* Surfaces surrounding the payload. */ - - cube_at(payload_width, front, payload_height, - 0, -1, 1, - payload_centre, -int_front_depth, int_payload_lower_extent); - - cube_at(front_left, front_depth, payload_height, - -1, -1, 1, - int_payload_left_extent, 0, int_payload_lower_extent); - - cube_at(front_right, front_depth, payload_height, - 1, -1, 1, - int_payload_right_extent, 0, int_payload_lower_extent); - - /* Surfaces surrounding the connector. */ - - cube_at(connector_width, front, connector_height, - 0, -1, -1, - 0, -int_front_depth, int_payload_lower_extent); - - cube_at(front_left, front_depth, connector_height, - -1, -1, -1, - -int_connector_width / 2, 0, int_payload_lower_extent); - - cube_at(front_right, front_depth, connector_height, - 1, -1, -1, - int_connector_width / 2, 0, int_payload_lower_extent); - - /* Top surface for the front piece. */ - - if (TOP_SURFACE) - cube_at(payload_width, front_depth, top, - 0, -1, 1, - payload_centre, 0, int_payload_upper_extent); - } - - difference() { - - /* Floor of cartridge. */ - - cube_at(int_connector_width, int_front_depth, bottom, - 0, -1, 1, - 0, 0, lower_extent + int_connector_height); - - /* Left cutout. */ - - cube_at(edge_connector_cutout_front_width, - edge_connector_cutout_front_depth, - bottom, - 1, -1, 1, - -int_connector_width / 2, - 0, - lower_extent + int_connector_height); - - /* Right cutout. */ - - cube_at(edge_connector_cutout_front_width, - edge_connector_cutout_front_depth, - bottom, - -1, -1, 1, - int_connector_width / 2, - 0, - lower_extent + int_connector_height); - } - - /* Extended floor. */ - - if (payload_width > connector_width) { - - cube_at(payload_width - connector_width, front_depth, bottom, - 1, -1, 1, - payload_left_extent, 0, lower_extent + int_connector_height); - } - - /* PCB supports. */ - - if (MODEL == ROM_CARTRIDGE) { - cube_at(pcb_front_support_width, - pcb_front_support_depth, - pcb_front_support_height, - -1, -1, 1, - -pcb_support_offset_from_centre, - 0, - int_payload_lower_extent); - - cube_at(pcb_front_support_width, - pcb_front_support_depth, - pcb_front_support_height, - 1, -1, 1, - pcb_support_offset_from_centre, - 0, - int_payload_lower_extent); - - /* Circular "lugs" to hold PCBs in place. */ - - pcb_front_lug(-1); - pcb_front_lug(1); - } - - if (MODEL == WIDE_CARTRIDGE) { - - pcb_front_lug_wide(-1); - pcb_front_lug_wide(1); - } - } - - /* Label insets. */ - - union() { - - /* Front label. */ - - if (FRONT_LABEL_INSET) - translate([front_label_left_extent, -front_depth, - lower_extent + front_label_offset_from_bottom]) - cube([front_label_width, front_label_depth, - front_label_height]); - - /* Top label. See also the back piece. */ - - if (TOP_LABEL_INSET) - translate([top_label_left_extent, - -front_depth + top_label_offset_from_front, - upper_extent - top_label_depth]) - cube([top_label_width, top_label_height, - top_label_depth]); - } - - /* Inner front edge cavity. */ - - translate([inner_front_edge_width / 2, -int_front_depth, lower_extent]) - rotate([0, -90, 0]) - linear_extrude(height = inner_front_edge_width) - polygon([ - [-extra, -inner_front_edge_depth], - [0, -inner_front_edge_depth], - [inner_front_edge_height, 0], - [-extra, 0], - ]); - - /* Inner top cutout for the top and sides of the back portion. */ - - cube_at(inner_top_front_cutout_width, - inner_top_front_cutout_depth, - inner_top_front_cutout_height, - 1, -1, 1, - int_payload_left_extent, 0, int_payload_upper_extent); - - cube_at(inner_payload_front_cutout_width, - inner_payload_front_cutout_depth, - inner_payload_front_cutout_height, - 1, -1, 1, - int_payload_right_extent, 0, int_payload_lower_extent); - - cube_at(inner_payload_front_cutout_width, - inner_payload_front_cutout_depth, - inner_payload_front_cutout_height, - -1, -1, 1, - int_payload_left_extent, 0, int_payload_lower_extent); - - if (BACK_CONNECTOR_SECTION) { - - /* Cutout to accept the back connector sides. */ - - cube_at(inner_connector_front_cutout_width, - inner_connector_front_cutout_depth, - inner_connector_front_cutout_height, - 1, -1, -1, - int_connector_width / 2, 0, int_payload_lower_extent); - - cube_at(inner_connector_front_cutout_width, - inner_connector_front_cutout_depth, - inner_connector_front_cutout_height, - -1, -1, -1, - -int_connector_width / 2, 0, int_payload_lower_extent); - } - - /* Fillets to round off the edges. */ - - union() { - if (ROUND_EDGES) { - - /* Top left and right rounding. */ - - translate([payload_left_extent + ro, -front_depth / 2, upper_extent - ro]) - rotate([0, 0, 180]) - rotate([90, 0, 0]) - fillet(rr, front_depth); - translate([payload_right_extent - ro, -front_depth / 2, upper_extent - ro]) - rotate([90, 0, 0]) - fillet(rr, front_depth); - - /* Top front rounding. */ - - translate([payload_centre, -front_depth + ro, upper_extent - ro]) - rotate([0, 0, 180]) - rotate([0, -90, 0]) - fillet(rr, payload_width); - - /* Edge rounding. */ - - translate([payload_right_extent - ro, -front_depth + ro, int_payload_lower_extent - bottom - extra]) - rotate([0, 0, 270]) - fillet_justified(rr, payload_height + bottom + extra); - - translate([payload_left_extent + ro, -front_depth + ro, int_payload_lower_extent - bottom - extra]) - rotate([0, 0, 180]) - fillet_justified(rr, payload_height + bottom + extra); - - translate([connector_width / 2 - ro, -front_depth + ro, lower_extent]) - rotate([0, 0, 270]) - fillet_partitioned(rr, connector_height - bottom); - - translate([-connector_width / 2 + ro, -front_depth + ro, lower_extent]) - rotate([0, 0, 180]) - fillet_partitioned(rr, connector_height - bottom); - } - } - } - - /* - Place the back piece next to the front, with the internals facing out - the same way, if APART is defined. - */ - - back_displacement = APART ? connector_width * 0.6 : 0; - back_rotation = APART ? 180 : 0; - - if (BACK) - translate([back_displacement, 0, 0]) - rotate([0, 0, back_rotation]) { + module front_piece(front_displacement, front_displacement_together) { + if (FRONT) + translate([front_displacement, front_displacement_together, 0]) difference() { /* The cartridge surfaces. */ union() { - /* Back portion. */ + /* Front portion. */ - if (BACK_SURFACE) { + if (FRONT_SURFACE) { /* Surfaces surrounding the payload. */ - /* Payload section of back surface. */ + cube_at(payload_width, front, payload_height, + 0, -1, 1, + payload_centre, -int_front_depth, int_payload_lower_extent); - cube_at(payload_width, payload_back, payload_height, - 0, 1, 1, - payload_centre, int_payload_back_depth, int_payload_lower_extent); - - cube_at(back_left, back_depth, payload_height, - -1, 1, 1, + cube_at(front_left, front_depth, payload_height, + -1, -1, 1, int_payload_left_extent, 0, int_payload_lower_extent); - cube_at(back_right, back_depth, payload_height, - 1, 1, 1, + cube_at(front_right, front_depth, payload_height, + 1, -1, 1, int_payload_right_extent, 0, int_payload_lower_extent); /* Surfaces surrounding the connector. */ - /* Connector section of back surface overlapping the floor. */ - - if (BACK_CONNECTOR_SECTION) { - cube_at(connector_width, connector_back, connector_height, - 0, 1, -1, - 0, int_connector_back_depth, int_payload_lower_extent); + cube_at(connector_width, front, connector_height, + 0, -1, -1, + 0, -int_front_depth, int_payload_lower_extent); - cube_at(back_left, back_depth, connector_height, - -1, 1, -1, - -int_connector_width / 2, 0, int_payload_lower_extent); + cube_at(front_left, front_depth, connector_height, + -1, -1, -1, + -int_connector_width / 2, 0, int_payload_lower_extent); - cube_at(back_right, back_depth, connector_height, - 1, 1, -1, - int_connector_width / 2, 0, int_payload_lower_extent); - } + cube_at(front_right, front_depth, connector_height, + 1, -1, -1, + int_connector_width / 2, 0, int_payload_lower_extent); - /* Top of back piece. */ + /* Top surface for the front piece. */ if (TOP_SURFACE) - cube_at(payload_width, back_depth, top, - 0, 1, 1, + cube_at(payload_width, front_depth, top, + 0, -1, 1, payload_centre, 0, int_payload_upper_extent); - - /* - The extension of the back to connect with the front. Here, the inside - edges are rounded. The outside edges are rounded later. - - An extra overlapping measure is employed so that the filleting is - continuous between the payload and connector portions. On the inside - edges, the connector filleting is extended upwards. - */ - - /* Left side of payload. */ - - difference() { - cube_at(back_left - groove_depth, groove_width_extra, inner_payload_front_cutout_height, - -1, 1, 1, - int_payload_left_extent, -groove_width_extra, int_payload_lower_extent); - if (ROUND_CONNECTING_EDGES) - translate([int_payload_left_extent - groove_ro, -groove_width_extra + groove_ro, - int_payload_lower_extent]) - rotate([0, 0, -90]) - fillet_justified(groove_rr, inner_payload_front_cutout_height); - } - - /* Right side of payload. */ - - difference() { - cube_at(back_right - groove_depth, groove_width_extra, inner_payload_front_cutout_height, - 1, 1, 1, - int_payload_right_extent, -groove_width_extra, int_payload_lower_extent); - if (ROUND_CONNECTING_EDGES) - translate([int_payload_right_extent + groove_ro, -groove_width_extra + groove_ro, - int_payload_lower_extent]) - rotate([0, 0, 180]) - fillet_justified(groove_rr, inner_payload_front_cutout_height); - } - - if (BACK_CONNECTOR_SECTION) { - - /* Left side of connector. */ - - difference() { - cube_at(back_left - groove_depth, groove_width_extra, inner_connector_front_cutout_height, - -1, 1, -1, - -int_connector_width / 2, -groove_width_extra, int_payload_lower_extent); - if (ROUND_CONNECTING_EDGES) - translate([-int_connector_width / 2 - groove_ro, -groove_width_extra + groove_ro, - lower_extent]) - rotate([0, 0, -90]) - fillet_partitioned(groove_rr, - inner_connector_front_cutout_height + extra); - } - - /* Right side of connector. */ - - difference() { - cube_at(back_right - groove_depth, groove_width_extra, inner_connector_front_cutout_height, - 1, 1, -1, - int_connector_width / 2, -groove_width_extra, int_payload_lower_extent); - if (ROUND_CONNECTING_EDGES) - translate([int_connector_width / 2 + groove_ro, -groove_width_extra + groove_ro, - lower_extent]) - rotate([0, 0, 180]) - fillet_partitioned(groove_rr, - inner_connector_front_cutout_height + extra); - } - } - - /* Top side. */ - - difference() { - cube_at(payload_width - groove_depth * 2, groove_width_extra, top - top_groove_depth, - 0, 1, 1, - payload_centre, -groove_width_extra, int_payload_upper_extent); - if (ROUND_CONNECTING_EDGES) - translate([payload_centre, -groove_width_extra + groove_ro, - int_payload_upper_extent + groove_ro]) - rotate([0, 0, 180]) - rotate([0, 90, 0]) - fillet(groove_rr, payload_width - groove_depth * 2); - } } difference() { /* Floor of cartridge. */ - cube_at(connector_width, back_depth, bottom, - 0, 1, 1, + cube_at(int_connector_width, int_front_depth, bottom, + 0, -1, 1, 0, 0, lower_extent + int_connector_height); - /* Edge connector cutout. */ + /* Left cutout. */ + + cube_at(edge_connector_cutout_front_width, + edge_connector_cutout_front_depth, + bottom, + 1, -1, 1, + -int_connector_width / 2, + 0, + lower_extent + int_connector_height); - cube_at(edge_connector_cutout_back_width, - edge_connector_cutout_back_depth, + /* Right cutout. */ + + cube_at(edge_connector_cutout_front_width, + edge_connector_cutout_front_depth, bottom, - 0, 1, 1, - 0, 0, lower_extent + int_connector_height); + -1, -1, 1, + int_connector_width / 2, + 0, + lower_extent + int_connector_height); } /* Extended floor. */ if (payload_width > connector_width) { - difference() { - - cube_at(payload_width - connector_width, back_depth, bottom, - 1, 1, 1, - payload_left_extent, 0, lower_extent + int_connector_height); - - cube_at(payload_width - connector_width, edge_connector_cutout_front_depth, bottom, - 1, 1, 1, - payload_left_extent, 0, lower_extent + int_connector_height); - } + cube_at(payload_width - connector_width, front_depth, bottom, + 1, -1, 1, + payload_left_extent, 0, lower_extent + int_connector_height); } /* PCB supports. */ if (MODEL == ROM_CARTRIDGE) { - pcb_support(-1, pcb_back_support_left_bump_height, - pcb_back_support_left_bump_offset_from_bottom); - pcb_support(1, pcb_back_support_right_bump_height, - pcb_back_support_right_bump_offset_from_bottom); + cube_at(pcb_front_support_width, + pcb_front_support_depth, + pcb_front_support_height, + -1, -1, 1, + -pcb_support_offset_from_centre, + 0, + int_payload_lower_extent); + + cube_at(pcb_front_support_width, + pcb_front_support_depth, + pcb_front_support_height, + 1, -1, 1, + pcb_support_offset_from_centre, + 0, + int_payload_lower_extent); /* Circular "lugs" to hold PCBs in place. */ - pcb_lug(-1); - pcb_lug(1); + pcb_front_lug(-1); + pcb_front_lug(1); } if (MODEL == WIDE_CARTRIDGE) { - pcb_lug_wide(1); - pcb_lug_wide(-1); + pcb_front_lug_wide(-1); + pcb_front_lug_wide(1); } } @@ -1022,7 +715,15 @@ union() { - /* Top label. See also the front piece. */ + /* Front label. */ + + if (FRONT_LABEL_INSET) + translate([front_label_left_extent, -front_depth, + lower_extent + front_label_offset_from_bottom]) + cube([front_label_width, front_label_depth, + front_label_height]); + + /* Top label. See also the back piece. */ if (TOP_LABEL_INSET) translate([top_label_left_extent, @@ -1032,106 +733,53 @@ top_label_depth]); } - /* Top and side grooves, positioned in the back portion. */ - - union() { - - /* Left groove. */ + /* Inner front edge cavity. */ - cube_at(groove_depth, groove_width_normal, height, - 1, 1, 0, - payload_left_extent, 0, 0); + translate([inner_front_edge_width / 2, -int_front_depth, lower_extent]) + rotate([0, -90, 0]) + linear_extrude(height = inner_front_edge_width) + polygon([ + [-extra, -inner_front_edge_depth], + [0, -inner_front_edge_depth], + [inner_front_edge_height, 0], + [-extra, 0], + ]); - /* Right groove. */ + /* Inner top cutout for the top and sides of the back portion. */ - cube_at(groove_depth, groove_width_normal, height, - -1, 1, 0, - payload_right_extent, 0, 0); - - /* Top grooves. */ + cube_at(inner_top_front_cutout_width, + inner_top_front_cutout_depth, + inner_top_front_cutout_height, + 1, -1, 1, + int_payload_left_extent, 0, int_payload_upper_extent); - cube_at(payload_width, groove_width_normal, groove_depth, - 0, 1, -1, - payload_centre, 0, upper_extent); + cube_at(inner_payload_front_cutout_width, + inner_payload_front_cutout_depth, + inner_payload_front_cutout_height, + 1, -1, 1, + int_payload_right_extent, 0, int_payload_lower_extent); - cube_at(payload_width, top_groove_width, top_groove_depth, - 0, 1, -1, - payload_centre, -groove_width_extra, upper_extent); - } + cube_at(inner_payload_front_cutout_width, + inner_payload_front_cutout_depth, + inner_payload_front_cutout_height, + -1, -1, 1, + int_payload_left_extent, 0, int_payload_lower_extent); if (BACK_CONNECTOR_SECTION) { - /* Back cavity. */ - - if (BACK_CAVITY) - intersection() { - - /* From the bottom upwards. */ - - translate([0, back_depth, lower_extent]) - linear_extrude(height = back_cavity_height) - translate([-int_connector_width / 2, 0, 0]) - polygon([ - [back_cavity_offset_from_inner_left, 0], - [back_cavity_inner_offset_from_inner_left, - -back_cavity_depth], - [back_cavity_inner_offset_from_inner_left + - back_cavity_inner_width, - -back_cavity_depth], - [back_cavity_offset_from_inner_left + - back_cavity_width, 0] - ]); - - /* From left to right. */ - - translate([back_cavity_width / 2, back_depth, lower_extent]) - rotate([0, -90, 0]) - linear_extrude(height = back_cavity_width) - polygon([ - [-extra, -back_cavity_depth], - [back_cavity_inner_height, - -back_cavity_depth], - [back_cavity_height, 0], - [-extra, 0] - ]); - } + /* Cutout to accept the back connector sides. */ - /* Inner back cavities. */ - - translate([0, int_connector_back_depth, lower_extent]) - linear_extrude(height = int_connector_height) - translate([-int_connector_width / 2, 0, 0]) - polygon([ - [0, 0], - [inner_back_slope_max_offset, 0], - [inner_back_slope_min_offset, - inner_back_slope_depth], - [0, inner_back_slope_depth] - ]); + cube_at(inner_connector_front_cutout_width, + inner_connector_front_cutout_depth, + inner_connector_front_cutout_height, + 1, -1, -1, + int_connector_width / 2, 0, int_payload_lower_extent); - translate([0, int_connector_back_depth, lower_extent]) - linear_extrude(height = int_connector_height) - translate([int_connector_width / 2, 0, 0]) - polygon([ - [0, 0], - [-inner_back_slope_max_offset, 0], - [-inner_back_slope_min_offset, - inner_back_slope_depth], - [0, inner_back_slope_depth] - ]); - - /* Inner back edge cavity. */ - - translate([inner_back_edge_width / 2, - int_connector_back_depth + inner_back_edge_depth, lower_extent]) - rotate([0, -90, 0]) - linear_extrude(height = inner_back_edge_width) - polygon([ - [-extra, -inner_back_edge_depth], - [inner_back_edge_height, -inner_back_edge_depth], - [0, 0], - [-extra, 0] - ]); + cube_at(inner_connector_front_cutout_width, + inner_connector_front_cutout_depth, + inner_connector_front_cutout_height, + -1, -1, -1, + -int_connector_width / 2, 0, int_payload_lower_extent); } /* Fillets to round off the edges. */ @@ -1141,214 +789,589 @@ /* Top left and right rounding. */ - translate([payload_left_extent + ro, back_depth / 2, upper_extent - ro]) + translate([payload_left_extent + ro, -front_depth / 2, upper_extent - ro]) rotate([0, 0, 180]) rotate([90, 0, 0]) - fillet(rr, back_depth); - translate([payload_right_extent - ro, back_depth / 2, upper_extent - ro]) + fillet(rr, front_depth); + translate([payload_right_extent - ro, -front_depth / 2, upper_extent - ro]) rotate([90, 0, 0]) - fillet(rr, back_depth); - - /* Top back rounding. */ + fillet(rr, front_depth); + + /* Top front rounding. */ - translate([payload_centre, back_depth - ro, upper_extent - ro]) - rotate([0, -90, 0]) - fillet(rr, payload_width); + translate([payload_centre, -front_depth + ro, upper_extent - ro]) + rotate([0, 0, 180]) + rotate([0, -90, 0]) + fillet(rr, payload_width); - /* Outer edge rounding. */ + /* Edge rounding. */ - translate([payload_right_extent - ro, back_depth - ro, int_payload_lower_extent - bottom - extra]) - fillet_justified(rr, payload_height + bottom + extra); - - translate([payload_left_extent + ro, back_depth - ro, int_payload_lower_extent - bottom - extra]) - rotate([0, 0, 90]) + translate([payload_right_extent - ro, -front_depth + ro, int_payload_lower_extent - bottom - extra]) + rotate([0, 0, 270]) fillet_justified(rr, payload_height + bottom + extra); - if (BACK_CONNECTOR_SECTION) { - translate([connector_width / 2 - ro, back_depth - ro, lower_extent]) + translate([payload_left_extent + ro, -front_depth + ro, int_payload_lower_extent - bottom - extra]) + rotate([0, 0, 180]) + fillet_justified(rr, payload_height + bottom + extra); + + translate([connector_width / 2 - ro, -front_depth + ro, lower_extent]) + rotate([0, 0, 270]) fillet_partitioned(rr, connector_height - bottom); - translate([-connector_width / 2 + ro, back_depth - ro, lower_extent]) - rotate([0, 0, 90]) - fillet_partitioned(rr, connector_height - bottom); - } - } - - if (ROUND_CONNECTING_EDGES) { - - /* - Outer edge rounding of the back extension. This is done as a - separate removal operation rather than occurring when creating the - extension in order to ensure that the edges are actually rounded. - - An extra overlapping measure is employed so that the filleting is - continuous between the payload and connector portions. On the outside - edges, the payload filleting is extended downwards. - */ - - translate([payload_left_extent + groove_depth + groove_ro, -groove_width_extra + groove_ro, - int_payload_lower_extent - extra]) + translate([-connector_width / 2 + ro, -front_depth + ro, lower_extent]) rotate([0, 0, 180]) - fillet_justified(groove_rr, inner_payload_front_cutout_height + extra); - - translate([payload_right_extent - groove_depth - groove_ro, -groove_width_extra + groove_ro, - int_payload_lower_extent - extra]) - rotate([0, 0, -90]) - fillet_justified(groove_rr, inner_payload_front_cutout_height + extra); - - /* Sides of connector. */ - - translate([-connector_width / 2 + groove_depth + groove_ro, -groove_width_extra + groove_ro, - lower_extent]) - rotate([0, 0, 180]) - fillet_partitioned(groove_rr, inner_connector_front_cutout_height); - - translate([connector_width / 2 - groove_depth - groove_ro, -groove_width_extra + groove_ro, - lower_extent]) - rotate([0, 0, -90]) - fillet_partitioned(groove_rr, inner_connector_front_cutout_height); - - /* Top of payload. */ - - translate([payload_centre, -groove_width_extra + groove_ro, - int_payload_upper_extent + inner_top_front_cutout_height - groove_ro]) - rotate([0, 0, 180]) - rotate([0, -90, 0]) - fillet(groove_rr, payload_width - groove_depth * 2); + fillet_partitioned(rr, connector_height - bottom); } } } + } - /* PCBs for checking. */ - - if (PCB) if (MODEL == ROM_CARTRIDGE) { - translate([0, 0, int_payload_lower_extent]) - difference() { + module back_piece(back_displacement, back_rotation) { + if (BACK) + translate([back_displacement, 0, 0]) + rotate([0, 0, back_rotation]) { + difference() { + + /* The cartridge surfaces. */ + + union() { + + /* Back portion. */ + + if (BACK_SURFACE) { + + /* Surfaces surrounding the payload. */ + + /* Payload section of back surface. */ + + cube_at(payload_width, payload_back, payload_height, + 0, 1, 1, + payload_centre, int_payload_back_depth, int_payload_lower_extent); + + cube_at(back_left, back_depth, payload_height, + -1, 1, 1, + int_payload_left_extent, 0, int_payload_lower_extent); + + cube_at(back_right, back_depth, payload_height, + 1, 1, 1, + int_payload_right_extent, 0, int_payload_lower_extent); + + /* Surfaces surrounding the connector. */ - /* Mock PCB. */ + /* Connector section of back surface overlapping the floor. */ + + if (BACK_CONNECTOR_SECTION) { + cube_at(connector_width, connector_back, connector_height, + 0, 1, -1, + 0, int_connector_back_depth, int_payload_lower_extent); + + cube_at(back_left, back_depth, connector_height, + -1, 1, -1, + -int_connector_width / 2, 0, int_payload_lower_extent); + + cube_at(back_right, back_depth, connector_height, + 1, 1, -1, + int_connector_width / 2, 0, int_payload_lower_extent); + } + + /* Top of back piece. */ + + if (TOP_SURFACE) + cube_at(payload_width, back_depth, top, + 0, 1, 1, + payload_centre, 0, int_payload_upper_extent); + + /* + The extension of the back to connect with the front. Here, the inside + edges are rounded. The outside edges are rounded later. + + An extra overlapping measure is employed so that the filleting is + continuous between the payload and connector portions. On the inside + edges, the connector filleting is extended upwards. + */ + + /* Left side of payload. */ - union() { - cube_at(pcb_width, pcb_depth, - pcb_height - edge_connector_height, - 0, -1, 1, - 0, edge_connector_cutout_back_depth, 0); - cube_at(edge_connector_width, pcb_depth, - edge_connector_height, - 0, -1, -1, - 0, edge_connector_cutout_back_depth, 0); + difference() { + cube_at(back_left - groove_depth, groove_width_extra, inner_payload_front_cutout_height, + -1, 1, 1, + int_payload_left_extent, -groove_width_extra, int_payload_lower_extent); + if (ROUND_CONNECTING_EDGES) + translate([int_payload_left_extent - groove_ro, -groove_width_extra + groove_ro, + int_payload_lower_extent]) + rotate([0, 0, -90]) + fillet_justified(groove_rr, inner_payload_front_cutout_height); + } + + /* Right side of payload. */ + + difference() { + cube_at(back_right - groove_depth, groove_width_extra, inner_payload_front_cutout_height, + 1, 1, 1, + int_payload_right_extent, -groove_width_extra, int_payload_lower_extent); + if (ROUND_CONNECTING_EDGES) + translate([int_payload_right_extent + groove_ro, -groove_width_extra + groove_ro, + int_payload_lower_extent]) + rotate([0, 0, 180]) + fillet_justified(groove_rr, inner_payload_front_cutout_height); + } + + if (BACK_CONNECTOR_SECTION) { + + /* Left side of connector. */ - /* Feature. */ + difference() { + cube_at(back_left - groove_depth, groove_width_extra, + inner_connector_front_cutout_height, + -1, 1, -1, + -int_connector_width / 2, -groove_width_extra, int_payload_lower_extent); + if (ROUND_CONNECTING_EDGES) + translate([-int_connector_width / 2 - groove_ro, + -groove_width_extra + groove_ro, + lower_extent]) + rotate([0, 0, -90]) + fillet_partitioned(groove_rr, + inner_connector_front_cutout_height + extra); + } + + /* Right side of connector. */ - cube_at(feature_width, feature_depth, feature_height, - 0, 1, 1, - 0, edge_connector_cutout_back_depth, feature_height_offset); + difference() { + cube_at(back_right - groove_depth, groove_width_extra, + inner_connector_front_cutout_height, + 1, 1, -1, + int_connector_width / 2, -groove_width_extra, int_payload_lower_extent); + if (ROUND_CONNECTING_EDGES) + translate([int_connector_width / 2 + groove_ro, + -groove_width_extra + groove_ro, + lower_extent]) + rotate([0, 0, 180]) + fillet_partitioned(groove_rr, + inner_connector_front_cutout_height + extra); + } + } + + /* Top side. */ + + difference() { + cube_at(payload_width - groove_depth * 2, groove_width_extra, top - top_groove_depth, + 0, 1, 1, + payload_centre, -groove_width_extra, int_payload_upper_extent); + if (ROUND_CONNECTING_EDGES) + translate([payload_centre, -groove_width_extra + groove_ro, + int_payload_upper_extent + groove_ro]) + rotate([0, 0, 180]) + rotate([0, 90, 0]) + fillet(groove_rr, payload_width - groove_depth * 2); + } } - /* Holes for mounting. */ + difference() { + + /* Floor of cartridge. */ + + cube_at(connector_width, back_depth, bottom, + 0, 1, 1, + 0, 0, lower_extent + int_connector_height); - union() { - cube_at(pcb_hole_width, pcb_hole_depth, pcb_left_hole_height, - -1, -1, 1, - pcb_left_hole_offset_from_centre, pcb_hole_start_depth, - pcb_left_hole_offset); - translate([pcb_left_hole_offset_from_centre - - pcb_hole_width / 2, pcb_hole_start_depth, pcb_left_hole_offset]) - rotate([90, 0, 0]) - cylinder(h=pcb_hole_depth, r=pcb_hole_width / 2); - translate([pcb_left_hole_offset_from_centre - - pcb_hole_width / 2, pcb_hole_start_depth, - pcb_left_hole_offset + pcb_left_hole_height]) - rotate([90, 0, 0]) - cylinder(h=pcb_hole_depth, r=pcb_hole_width / 2); + /* Edge connector cutout. */ + + cube_at(edge_connector_cutout_back_width, + edge_connector_cutout_back_depth, + bottom, + 0, 1, 1, + 0, 0, lower_extent + int_connector_height); } - union() { - cube_at(pcb_hole_width, pcb_hole_depth, pcb_right_hole_height, - 1, -1, 1, - pcb_right_hole_offset_from_centre, pcb_hole_start_depth, - pcb_right_hole_offset); - translate([pcb_right_hole_offset_from_centre + - pcb_hole_width / 2, pcb_hole_start_depth, pcb_right_hole_offset]) - rotate([90, 0, 0]) - cylinder(h=pcb_hole_depth, r=pcb_hole_width / 2); - translate([pcb_right_hole_offset_from_centre + - pcb_hole_width / 2, pcb_hole_start_depth, - pcb_right_hole_offset + pcb_right_hole_height]) - rotate([90, 0, 0]) - cylinder(h=pcb_hole_depth, r=pcb_hole_width / 2); + /* Extended floor. */ + + if (payload_width > connector_width) { + + difference() { + + cube_at(payload_width - connector_width, back_depth, bottom, + 1, 1, 1, + payload_left_extent, 0, lower_extent + int_connector_height); + + cube_at(payload_width - connector_width, edge_connector_cutout_front_depth, bottom, + 1, 1, 1, + payload_left_extent, 0, lower_extent + int_connector_height); + } + } + + /* PCB supports. */ + + if (MODEL == ROM_CARTRIDGE) { + pcb_support(-1, pcb_back_support_left_bump_height, + pcb_back_support_left_bump_offset_from_bottom); + pcb_support(1, pcb_back_support_right_bump_height, + pcb_back_support_right_bump_offset_from_bottom); + + /* Circular "lugs" to hold PCBs in place. */ + + pcb_lug(-1); + pcb_lug(1); } - /* Holes for lugs. */ + if (MODEL == WIDE_CARTRIDGE) { + + pcb_lug_wide(1); + pcb_lug_wide(-1); + } + } + + /* Label insets. */ + + union() { + + /* Top label. See also the front piece. */ - translate([ - -int_connector_width / 2 + pcb_lug_offset_from_inside, - pcb_hole_start_depth, pcb_lug_offset_from_bottom]) - rotate([90, 0, 0]) - cylinder(h=pcb_hole_depth, r=pcb_lug_hole_radius); + if (TOP_LABEL_INSET) + translate([top_label_left_extent, + -front_depth + top_label_offset_from_front, + upper_extent - top_label_depth]) + cube([top_label_width, top_label_height, + top_label_depth]); + } + + /* Top and side grooves, positioned in the back portion. */ + + union() { + + /* Left groove. */ + + cube_at(groove_depth, groove_width_normal, height, + 1, 1, 0, + payload_left_extent, 0, 0); + + /* Right groove. */ - translate([ - int_connector_width / 2 - pcb_lug_offset_from_inside, - pcb_hole_start_depth, pcb_lug_offset_from_bottom]) - rotate([90, 0, 0]) - cylinder(h=pcb_hole_depth, r=pcb_lug_hole_radius); + cube_at(groove_depth, groove_width_normal, height, + -1, 1, 0, + payload_right_extent, 0, 0); + + /* Top grooves. */ + + cube_at(payload_width, groove_width_normal, groove_depth, + 0, 1, -1, + payload_centre, 0, upper_extent); + + cube_at(payload_width, top_groove_width, top_groove_depth, + 0, 1, -1, + payload_centre, -groove_width_extra, upper_extent); } - } + + if (BACK_CONNECTOR_SECTION) { + + /* Back cavity. */ + + if (BACK_CAVITY) + intersection() { + + /* From the bottom upwards. */ + + translate([0, back_depth, lower_extent]) + linear_extrude(height = back_cavity_height) + translate([-int_connector_width / 2, 0, 0]) + polygon([ + [back_cavity_offset_from_inner_left, 0], + [back_cavity_inner_offset_from_inner_left, + -back_cavity_depth], + [back_cavity_inner_offset_from_inner_left + + back_cavity_inner_width, + -back_cavity_depth], + [back_cavity_offset_from_inner_left + + back_cavity_width, 0] + ]); + + /* From left to right. */ - if (PCB) if (MODEL == WIDE_CARTRIDGE) { - translate([0, 0, int_payload_lower_extent]) - difference() { + translate([back_cavity_width / 2, back_depth, lower_extent]) + rotate([0, -90, 0]) + linear_extrude(height = back_cavity_width) + polygon([ + [-extra, -back_cavity_depth], + [back_cavity_inner_height, + -back_cavity_depth], + [back_cavity_height, 0], + [-extra, 0] + ]); + } + + /* Inner back cavities. */ - /* Mock PCB. */ + translate([0, int_connector_back_depth, lower_extent]) + linear_extrude(height = int_connector_height) + translate([-int_connector_width / 2, 0, 0]) + polygon([ + [0, 0], + [inner_back_slope_max_offset, 0], + [inner_back_slope_min_offset, + inner_back_slope_depth], + [0, inner_back_slope_depth] + ]); + + translate([0, int_connector_back_depth, lower_extent]) + linear_extrude(height = int_connector_height) + translate([int_connector_width / 2, 0, 0]) + polygon([ + [0, 0], + [-inner_back_slope_max_offset, 0], + [-inner_back_slope_min_offset, + inner_back_slope_depth], + [0, inner_back_slope_depth] + ]); + + /* Inner back edge cavity. */ - union() { - cube_at(wide_pcb_width, wide_pcb_depth, - wide_pcb_height - edge_connector_height, - 0, -1, 1, - payload_centre, edge_connector_cutout_back_depth, 0); - cube_at(edge_connector_width, wide_pcb_depth, - edge_connector_height, - 0, -1, -1, - 0, edge_connector_cutout_back_depth, 0); + translate([inner_back_edge_width / 2, + int_connector_back_depth + inner_back_edge_depth, lower_extent]) + rotate([0, -90, 0]) + linear_extrude(height = inner_back_edge_width) + polygon([ + [-extra, -inner_back_edge_depth], + [inner_back_edge_height, -inner_back_edge_depth], + [0, 0], + [-extra, 0] + ]); + } + + /* Fillets to round off the edges. */ + + union() { + if (ROUND_EDGES) { - /* Feature. */ + /* Top left and right rounding. */ + + translate([payload_left_extent + ro, back_depth / 2, upper_extent - ro]) + rotate([0, 0, 180]) + rotate([90, 0, 0]) + fillet(rr, back_depth); + translate([payload_right_extent - ro, back_depth / 2, upper_extent - ro]) + rotate([90, 0, 0]) + fillet(rr, back_depth); + + /* Top back rounding. */ + + translate([payload_centre, back_depth - ro, upper_extent - ro]) + rotate([0, -90, 0]) + fillet(rr, payload_width); - cube_at(feature_width, feature_depth, feature_height, - 0, 1, 1, - 0, edge_connector_cutout_back_depth, feature_height_offset); + /* Outer edge rounding. */ + + translate([payload_right_extent - ro, back_depth - ro, int_payload_lower_extent - bottom - extra]) + fillet_justified(rr, payload_height + bottom + extra); + + translate([payload_left_extent + ro, back_depth - ro, int_payload_lower_extent - bottom - extra]) + rotate([0, 0, 90]) + fillet_justified(rr, payload_height + bottom + extra); + + if (BACK_CONNECTOR_SECTION) { + translate([connector_width / 2 - ro, back_depth - ro, lower_extent]) + fillet_partitioned(rr, connector_height - bottom); + + translate([-connector_width / 2 + ro, back_depth - ro, lower_extent]) + rotate([0, 0, 90]) + fillet_partitioned(rr, connector_height - bottom); + } } - /* Holes for lugs. */ + if (ROUND_CONNECTING_EDGES) { + + /* + Outer edge rounding of the back extension. This is done as a + separate removal operation rather than occurring when creating the + extension in order to ensure that the edges are actually rounded. + + An extra overlapping measure is employed so that the filleting is + continuous between the payload and connector portions. On the outside + edges, the payload filleting is extended downwards. + */ + + translate([payload_left_extent + groove_depth + groove_ro, -groove_width_extra + groove_ro, + int_payload_lower_extent - extra]) + rotate([0, 0, 180]) + fillet_justified(groove_rr, inner_payload_front_cutout_height + extra); + + translate([payload_right_extent - groove_depth - groove_ro, -groove_width_extra + groove_ro, + int_payload_lower_extent - extra]) + rotate([0, 0, -90]) + fillet_justified(groove_rr, inner_payload_front_cutout_height + extra); + + /* Sides of connector. */ + + translate([-connector_width / 2 + groove_depth + groove_ro, -groove_width_extra + groove_ro, + lower_extent]) + rotate([0, 0, 180]) + fillet_partitioned(groove_rr, inner_connector_front_cutout_height); + + translate([connector_width / 2 - groove_depth - groove_ro, -groove_width_extra + groove_ro, + lower_extent]) + rotate([0, 0, -90]) + fillet_partitioned(groove_rr, inner_connector_front_cutout_height); + + /* Top of payload. */ - translate([ - payload_centre + int_payload_width / 2 - wide_pcb_lug_offset_from_inside , - wide_pcb_hole_start_depth, - wide_pcb_height - edge_connector_height - wide_pcb_lug_offset_from_bottom]) - rotate([90, 0, 0]) - cylinder(h=wide_pcb_hole_depth, r=wide_pcb_lug_hole_radius); + translate([payload_centre, -groove_width_extra + groove_ro, + int_payload_upper_extent + inner_top_front_cutout_height - groove_ro]) + rotate([0, 0, 180]) + rotate([0, -90, 0]) + fillet(groove_rr, payload_width - groove_depth * 2); + } + } + } + + /* PCBs for checking. */ + + if (PCB) if (MODEL == ROM_CARTRIDGE) { + translate([0, 0, int_payload_lower_extent]) + difference() { + + /* Mock PCB. */ - translate([ - payload_centre - int_payload_width / 2 + wide_pcb_lug_offset_from_inside , - wide_pcb_hole_start_depth, - wide_pcb_height - edge_connector_height - wide_pcb_lug_offset_from_bottom]) - rotate([90, 0, 0]) - cylinder(h=wide_pcb_hole_depth, r=wide_pcb_lug_hole_radius); + union() { + cube_at(pcb_width, pcb_depth, + pcb_height - edge_connector_height, + 0, -1, 1, + 0, edge_connector_cutout_back_depth, 0); + cube_at(edge_connector_width, pcb_depth, + edge_connector_height, + 0, -1, -1, + 0, edge_connector_cutout_back_depth, 0); + + /* Feature. */ + + cube_at(feature_width, feature_depth, feature_height, + 0, 1, 1, + 0, edge_connector_cutout_back_depth, feature_height_offset); + } + + /* Holes for mounting. */ + + union() { + cube_at(pcb_hole_width, pcb_hole_depth, pcb_left_hole_height, + -1, -1, 1, + pcb_left_hole_offset_from_centre, pcb_hole_start_depth, + pcb_left_hole_offset); + translate([pcb_left_hole_offset_from_centre - + pcb_hole_width / 2, pcb_hole_start_depth, pcb_left_hole_offset]) + rotate([90, 0, 0]) + cylinder(h=pcb_hole_depth, r=pcb_hole_width / 2); + translate([pcb_left_hole_offset_from_centre - + pcb_hole_width / 2, pcb_hole_start_depth, + pcb_left_hole_offset + pcb_left_hole_height]) + rotate([90, 0, 0]) + cylinder(h=pcb_hole_depth, r=pcb_hole_width / 2); + } - translate([ - payload_centre + int_payload_width / 2 - wide_pcb_lug_offset_from_inside , - wide_pcb_hole_start_depth, - wide_pcb_lug_offset_from_bottom]) - rotate([90, 0, 0]) - cylinder(h=wide_pcb_hole_depth, r=wide_pcb_lug_hole_radius); + union() { + cube_at(pcb_hole_width, pcb_hole_depth, pcb_right_hole_height, + 1, -1, 1, + pcb_right_hole_offset_from_centre, pcb_hole_start_depth, + pcb_right_hole_offset); + translate([pcb_right_hole_offset_from_centre + + pcb_hole_width / 2, pcb_hole_start_depth, pcb_right_hole_offset]) + rotate([90, 0, 0]) + cylinder(h=pcb_hole_depth, r=pcb_hole_width / 2); + translate([pcb_right_hole_offset_from_centre + + pcb_hole_width / 2, pcb_hole_start_depth, + pcb_right_hole_offset + pcb_right_hole_height]) + rotate([90, 0, 0]) + cylinder(h=pcb_hole_depth, r=pcb_hole_width / 2); + } + + /* Holes for lugs. */ + + translate([ + -int_connector_width / 2 + pcb_lug_offset_from_inside, + pcb_hole_start_depth, pcb_lug_offset_from_bottom]) + rotate([90, 0, 0]) + cylinder(h=pcb_hole_depth, r=pcb_lug_hole_radius); + + translate([ + int_connector_width / 2 - pcb_lug_offset_from_inside, + pcb_hole_start_depth, pcb_lug_offset_from_bottom]) + rotate([90, 0, 0]) + cylinder(h=pcb_hole_depth, r=pcb_lug_hole_radius); + } + } + + if (PCB) if (MODEL == WIDE_CARTRIDGE) { + translate([0, 0, int_payload_lower_extent]) + difference() { + + /* Mock PCB. */ + + union() { + cube_at(wide_pcb_width, wide_pcb_depth, + wide_pcb_height - edge_connector_height, + 0, -1, 1, + payload_centre, edge_connector_cutout_back_depth, 0); + cube_at(edge_connector_width, wide_pcb_depth, + edge_connector_height, + 0, -1, -1, + 0, edge_connector_cutout_back_depth, 0); + + /* Feature. */ - translate([ - payload_centre - int_payload_width / 2 + wide_pcb_lug_offset_from_inside , - wide_pcb_hole_start_depth, - wide_pcb_lug_offset_from_bottom]) - rotate([90, 0, 0]) - cylinder(h=wide_pcb_hole_depth, r=wide_pcb_lug_hole_radius); - } + cube_at(feature_width, feature_depth, feature_height, + 0, 1, 1, + 0, edge_connector_cutout_back_depth, feature_height_offset); + } + + /* Holes for lugs. */ + + translate([ + payload_centre + int_payload_width / 2 - wide_pcb_lug_offset_from_inside , + wide_pcb_hole_start_depth, + wide_pcb_height - edge_connector_height - wide_pcb_lug_offset_from_bottom]) + rotate([90, 0, 0]) + cylinder(h=wide_pcb_hole_depth, r=wide_pcb_lug_hole_radius); + + translate([ + payload_centre - int_payload_width / 2 + wide_pcb_lug_offset_from_inside , + wide_pcb_hole_start_depth, + wide_pcb_height - edge_connector_height - wide_pcb_lug_offset_from_bottom]) + rotate([90, 0, 0]) + cylinder(h=wide_pcb_hole_depth, r=wide_pcb_lug_hole_radius); + + translate([ + payload_centre + int_payload_width / 2 - wide_pcb_lug_offset_from_inside , + wide_pcb_hole_start_depth, + wide_pcb_lug_offset_from_bottom]) + rotate([90, 0, 0]) + cylinder(h=wide_pcb_hole_depth, r=wide_pcb_lug_hole_radius); + + translate([ + payload_centre - int_payload_width / 2 + wide_pcb_lug_offset_from_inside , + wide_pcb_hole_start_depth, + wide_pcb_lug_offset_from_bottom]) + rotate([90, 0, 0]) + cylinder(h=wide_pcb_hole_depth, r=wide_pcb_lug_hole_radius); + } + } } + } + + /* + Place the back piece next to the front, with the internals facing out + the same way, if APART is defined. + */ + + front_displacement_together = CLOSED ? front_back_overlap : 0; + front_displacement = APART ? -connector_width * 0.6 : 0; + back_displacement = APART ? connector_width * 0.6 : 0; + back_rotation = APART ? 180 : 0; + + if (INTERSECT) { + intersection() { + front_piece(0, front_displacement_together); + back_piece(0, 0); } + } else { + front_piece(front_displacement, front_displacement_together); + back_piece(back_displacement, back_rotation); + } } cartridge();