1 /* 2 Copyright (C) 2014, 2015, 2016 Paul Boddie 3 4 This program is free software; you can redistribute it and/or modify it under 5 the terms of the GNU General Public License as published by the Free Software 6 Foundation; either version 3 of the License, or (at your option) any later 7 version. 8 9 This program is distributed in the hope that it will be useful, but WITHOUT 10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 more details. 13 14 You should have received a copy of the GNU General Public License along with 15 this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 module cartridge() 19 { 20 $fn = 50; 21 22 /* Model configurations. Do not edit! */ 23 24 ROM_CARTRIDGE = 0; 25 WIDE_CARTRIDGE = 1; 26 27 /* Set this to the desired model type. */ 28 29 MODEL = ROM_CARTRIDGE; 30 31 /* 32 Configure the generated shapes. 33 For the absolute simplest shape (for basic 3D printers)... 34 35 BACK_CONNECTOR_SECTION = 0; 36 FRONT_LABEL_INSET = 0; TOP_LABEL_INSET = 0; 37 GROOVE = 0; ROUND_EDGES = 0; ROUND_CONNECTING_EDGES = 0; 38 39 Leave all options enabled for more capable 3D printers. 40 */ 41 42 /* The back part of the connecting section of the cartridge. */ 43 BACK_CONNECTOR_SECTION = 1; 44 45 /* A necessary exterior cavity to let the cartridge fit inside the slot. */ 46 BACK_CAVITY = 1; 47 48 /* Optional insets for labels. */ 49 FRONT_LABEL_INSET = 1; 50 TOP_LABEL_INSET = 1; 51 52 /* Optional groove between the pieces to match the Electron. */ 53 GROOVE = 1; 54 55 /* Optional rounding of the external edges. */ 56 ROUND_EDGES = 1; 57 58 /* Recommended rounding of connection edges. */ 59 ROUND_CONNECTING_EDGES = 1; 60 61 /* Set this where a shorter PCB is to be used. */ 62 63 SHORT_PCB = 0; 64 65 /* 66 Options for checking. Some useful combinations... 67 68 Check feature alignment: APART = 0; BACK_SURFACE = 0; FRONT_SURFACE = 0; 69 Check PCB alignment: PCB = 1; BACK_SURFACE = 0; 70 */ 71 72 BACK = 1; BACK_SURFACE = 1; 73 FRONT = 1; FRONT_SURFACE = 1; 74 TOP_SURFACE = 1; 75 76 /* For printing: APART = 1; PCB = 0; */ 77 78 APART = 1; 79 SPACE_APART = 10; 80 PCB = 0; 81 82 /* To check overlaps: INTERSECT = 1; CLOSED = 1; */ 83 84 INTERSECT = 0; 85 CLOSED = 0; 86 87 /* To save time (before printing): FILLET = 0; */ 88 89 FILLET = 1; 90 91 /* 92 Rounding/fillet radius and additional margin of subtracted 93 material. The additional margin helps avoid geometry problems. 94 */ 95 96 rr = 2; 97 ro = rr; 98 extra = 0.1; 99 100 groove_rr = 0.2; 101 groove_ro = groove_rr; 102 103 pcb_lug_rr = 0.5; 104 pcb_lug_ro = pcb_lug_rr; 105 106 /* A fillet performs rounding using a quarter segment of a cylinder. */ 107 108 module fillet(r, h) { 109 if (FILLET) 110 translate([0, 0, -h/2]) 111 difference() { 112 cube([r + extra, r + extra, h + extra]); 113 cylinder(r = r, h = h); 114 } 115 } 116 117 /* A fillet justified using the axes. */ 118 119 module fillet_justified(r, h) { 120 if (FILLET) 121 difference() { 122 cube([r + extra, r + extra, h + extra]); 123 cylinder(r = r, h = h); 124 } 125 } 126 127 /* A justified fillet with the extra material below the y-axis. */ 128 129 module fillet_partitioned(r, h) { 130 if (FILLET) 131 difference() { 132 translate([0, 0, -extra]) 133 cube([r + extra, r + extra, h + extra]); 134 cylinder(r = r, h = h); 135 } 136 } 137 138 module fillet_torus(radius, rounding) { 139 if (FILLET) 140 difference() { 141 cube_at((radius + extra) * 2, (radius + extra) * 2, rounding + extra, 142 0, 0, 1, 143 0, 0, 0); 144 union() { 145 rotate_extrude(convexity = 10) 146 translate([radius - rounding, 0, 0]) 147 circle(r = rounding); 148 cylinder(r = radius - rounding, h = rounding); 149 } 150 } 151 } 152 153 /* 154 Justify an object of the given dimensions, according to the given 155 factors (where 1 indicates moving the object to the positive side of an 156 axis, and -1 indicates moving it to the negative side of an axis). 157 158 NOTE: child should eventually be replaced by children. 159 */ 160 module justify(width, depth, height, wdir, ddir, hdir) { 161 translate([ 162 wdir * width / 2, 163 ddir * depth / 2, 164 hdir * height / 2]) 165 child(); 166 } 167 168 /* 169 Make a cuboid of the given dimensions, justifying it according to the given 170 factors, and moving it to the specified coordinates. 171 172 NOTE: Usage of justify within this module will not work due to recursion 173 NOTE: limitations in openscad, potentially removed in more recent 174 NOTE: releases. Thus, the justify transform is merged in here. 175 */ 176 module cube_at(width, depth, height, wdir, ddir, hdir, x, y, z) { 177 translate([ 178 x + wdir * width / 2, 179 y + ddir * depth / 2, 180 z + hdir * height / 2]) 181 cube([width, depth, height], center = true); 182 } 183 184 /* Model widths. */ 185 186 ROM_CARTRIDGE_int_payload_width = 86.0; 187 WIDE_CARTRIDGE_int_payload_width = 140.0; 188 189 /* Internal dimensions. */ 190 191 /* internal width in the payload section */ 192 int_payload_width = 193 MODEL == ROM_CARTRIDGE ? ROM_CARTRIDGE_int_payload_width : 194 MODEL == WIDE_CARTRIDGE ? WIDE_CARTRIDGE_int_payload_width : 195 ROM_CARTRIDGE_int_payload_width; 196 197 int_connector_width = 86.0; /* limited to the Plus 1 socket dimensions */ 198 int_payload_depth = 14.0; /* maximum depth in the payload section */ 199 int_connector_depth = 11.5; /* maximum depth in the connector section */ 200 int_payload_height = 50.8; /* space between the top and the floor */ 201 int_connector_height = 13.5; /* vertical offset of bottom/floor of payload area */ 202 203 /* Side thicknesses. */ 204 205 front = 2; 206 payload_back = 1; /* in the payload area the thickness is reduced */ 207 connector_back = 3.5; /* the back cavity requires a thicker back wall */ 208 top = 3; 209 side = 2; /* increased from 1.5 for 3D printing reliability */ 210 bottom = 1; /* thickness of floor of payload area */ 211 212 /* How much extra depth the back provides for mating with the front. */ 213 214 groove_width_extra = 2.0; /* the depth of the groove accommodating the front rim */ 215 front_back_overlap = 1.0; 216 groove_width_overlap = front_back_overlap + groove_width_extra; 217 218 /* Division of pieces into front and back, defining the extents. */ 219 220 int_front_depth = 4.5; 221 front_depth = int_front_depth + front; 222 int_payload_back_depth = int_payload_depth - int_front_depth + front_back_overlap; 223 int_connector_back_depth = int_connector_depth - int_front_depth + front_back_overlap; 224 back_depth = int_payload_back_depth + payload_back; 225 226 /* Cartridge dimensions. */ 227 228 payload_width = int_payload_width + side + side; 229 payload_height = top + int_payload_height; 230 231 connector_width = int_connector_width + side + side; 232 connector_height = bottom + int_connector_height; 233 234 height = payload_height + bottom + int_connector_height; 235 depth = int_payload_depth + front + payload_back; 236 237 upper_extent = height / 2; 238 lower_extent = -upper_extent; 239 int_payload_upper_extent = upper_extent - top; 240 int_payload_lower_extent = lower_extent + int_connector_height + bottom; 241 242 /* Connector extents. */ 243 244 int_connector_right_extent = int_connector_width / 2; 245 int_connector_left_extent = -int_connector_right_extent; 246 connector_left_extent = int_connector_left_extent - side; 247 connector_right_extent = int_connector_right_extent + side; 248 249 /* Where the payload is wider than the connector, the payload expands to the left. */ 250 251 int_payload_right_extent = int_connector_right_extent; 252 int_payload_left_extent = int_payload_right_extent - int_payload_width; 253 payload_left_extent = int_payload_left_extent - side; 254 payload_right_extent = int_payload_right_extent + side; 255 payload_centre = (payload_left_extent + payload_right_extent) / 2; 256 257 /* Cartridge surfaces. */ 258 259 front_side = side; 260 front_left = front_side; 261 front_right = front_side; 262 back_side = side; 263 back_left = back_side; 264 back_right = back_side; 265 266 /* Label details. */ 267 268 front_label_width = payload_width - side - side - 3.0; 269 front_label_height = 46.0; 270 front_label_depth = 1.0; 271 front_label_offset_from_bottom = 19.5; 272 front_label_centre = payload_centre; 273 front_label_left_extent = front_label_centre - front_label_width / 2; 274 275 top_label_width = front_label_width; 276 top_label_height = 11.5; /* the height as seen from above */ 277 top_label_depth = front_label_depth; 278 top_label_offset_from_front = 2.5; 279 top_label_centre = payload_centre; 280 top_label_left_extent = top_label_centre - front_label_width / 2; 281 282 /* 283 The groove around the sides and top. This is extended to allow the 284 pieces to fit together, and this extension is generated regardless of 285 whether the visible groove is enabled or not. 286 */ 287 288 groove_width_exposed = GROOVE ? 1.5 : 0; 289 groove_width_normal = groove_width_exposed + front_back_overlap; 290 groove_depth = 1.0; /* how deep the groove goes into each side */ 291 292 /* Additional cutting to mate the back and front. */ 293 294 top_groove_width = groove_width_overlap; 295 top_groove_depth = 2.0; 296 297 /* 298 Space for the inner edge of the back inside the front. 299 Offsets are measured from the outside surfaces. 300 */ 301 302 inner_top_front_cutout_width = int_payload_width; 303 inner_top_front_cutout_depth = top_groove_width; 304 inner_top_front_cutout_height = top - top_groove_depth; 305 306 inner_payload_front_cutout_height = payload_height - top_groove_depth; 307 inner_payload_front_cutout_width = front_side - groove_depth; 308 inner_payload_front_cutout_depth = groove_width_overlap; 309 310 inner_connector_front_cutout_height = connector_height; 311 inner_connector_front_cutout_width = front_side - groove_depth; 312 inner_connector_front_cutout_depth = groove_width_overlap; 313 314 /* 315 The back cavity is the indented part at the bottom of the back of the 316 cartridge. It appears to be mechanically necessary, making sure that 317 cartridges cannot be plugged in the wrong way round. 318 */ 319 320 back_cavity_width = 68.0; 321 back_cavity_inner_width = 65.0; 322 back_cavity_offset_from_inner_left = 9.0; 323 back_cavity_inner_offset_from_inner_left = 10.5; 324 back_cavity_height = 13.5; 325 back_cavity_inner_height = 12.0; 326 back_cavity_depth = 1.5; 327 328 /* 329 The effect of the cavity on the inside of the case. In principle, the 330 interior of the case could be straight since the plastic guides of the 331 Plus 1 socket are outside the case. 332 */ 333 334 inner_back_slope_depth = 2.5; 335 inner_back_slope_width = inner_back_slope_depth; 336 inner_back_slope_max_offset = 10.5; 337 inner_back_slope_min_offset = inner_back_slope_max_offset - inner_back_slope_width; 338 339 /* The tapering off of the inner back edge. */ 340 341 inner_back_edge_width = 69.0; 342 inner_back_edge_height = 3.0; 343 inner_back_edge_depth = 1.5; 344 345 /* The tapering off of the inner front edge. */ 346 347 inner_front_edge_width = connector_width - front_side * 2; 348 inner_front_edge_height = 3.0; 349 inner_front_edge_depth = 1.5; 350 351 /* 352 The cutout in the floor of the back of the cartridge that accommodates 353 the edge connector. 354 */ 355 356 edge_connector_cutout_back_depth = 3.0; 357 edge_connector_cutout_back_width = 57.5; 358 359 /* 360 The cutouts in the floor of the front of the cartridge that produce a 361 kind of tab that guides the edge connector into place in the back cutout. 362 */ 363 364 edge_connector_cutout_front_depth = front_back_overlap; 365 edge_connector_cutout_front_width = (int_connector_width - edge_connector_cutout_back_width) / 2; 366 367 /* 368 Edge connectors are themselves 0.05" or approximately 1.27mm in 369 thickness according to the Acorn Electron Cartridge Interface Specification 370 (Acorn Support Application Group Note 014). 371 */ 372 373 /* Extra internal features. Depths include front and back surfaces. */ 374 375 pcb_back_support_width = 1.2; 376 pcb_back_support_depth = back_depth - 377 edge_connector_cutout_back_depth; 378 pcb_back_support_height = height - int_connector_height - top - bottom; 379 380 pcb_front_support_width = 1.2; 381 pcb_front_support_depth = int_front_depth; 382 pcb_front_support_height = pcb_back_support_height; 383 384 /* 385 Features measured from the Stardot Dual ROM Adaptor cartridge board 386 dimensions diagram. Offsets are from inside the bottom "floor". 387 */ 388 389 pcb_back_support_bump_width = pcb_front_support_width; 390 pcb_back_support_bump_depth = 1.5; 391 pcb_back_support_left_bump_height = 13.2; 392 pcb_back_support_right_bump_height = 10.7; 393 pcb_back_support_left_bump_offset_from_bottom = 15.1; 394 pcb_back_support_right_bump_offset_from_bottom = 17.6; 395 396 /* Configured by SHORT_PCB. */ 397 pcb_back_support_top_bump_height = 3.8; 398 399 /* Move the PCB support towards the centre. */ 400 pcb_support_margin = 1.75; 401 pcb_support_offset_from_centre = edge_connector_cutout_back_width / 2 402 - pcb_support_margin; 403 404 /* 405 The PCB lugs protrude through the holes in the PCB. By extending both 406 the front and back lugs by the depth of the back support bump, they 407 overlap by that amount. The "mating" depth is defined as that amount 408 plus an additional amount for adhesion. 409 */ 410 411 pcb_lug_mating_depth = pcb_back_support_bump_depth + 1.0; 412 413 pcb_lug_depth = pcb_back_support_depth + 414 pcb_lug_mating_depth; 415 pcb_lug_inner_radius = 1.0; 416 pcb_lug_outer_radius = 5.5 / 2; 417 pcb_lug_offset_from_bottom = 14.35; 418 pcb_lug_offset_from_inside = 5.55; 419 420 /* 421 The cross detail on the back lug is intended to resist the front lug, 422 and thus starts at the point that the front lug ends. 423 */ 424 425 pcb_lug_cross_width = 6.7; 426 pcb_lug_cross_depth = pcb_back_support_depth + pcb_back_support_bump_depth - 427 pcb_lug_mating_depth; 428 pcb_lug_cross_height = 1.4; 429 430 pcb_front_lug_depth = pcb_front_support_depth + 431 pcb_lug_mating_depth; 432 pcb_front_lug_inner_radius = pcb_lug_outer_radius; 433 pcb_front_lug_outer_radius = pow( 434 pow(pcb_lug_cross_width / 2, 2) + 435 pow(pcb_lug_cross_height / 2, 2), 436 0.5); 437 438 wide_pcb_lug_offset_from_inside = 6.0; 439 wide_pcb_lug_offset_from_bottom = 6.0; 440 441 /* PCBs for checking. */ 442 443 pcb_width = 84.85; pcb_height = 62.5; pcb_depth = 1; 444 edge_connector_width = 56.5; edge_connector_height = 11.85; 445 446 /* 447 The rectangular part of the narrow left and right holes is smaller 448 than the "bump" in the case, but the circular parts make the overall 449 hole larger than the "bump". An extra depth is used for holes to avoid 450 surface definition problems. 451 */ 452 453 pcb_hole_margin = 0.55; 454 pcb_hole_width = 2.2; 455 pcb_hole_extra_depth = 0.1; 456 pcb_lug_hole_radius = 3.75; 457 458 pcb_left_hole_offset = pcb_back_support_left_bump_offset_from_bottom + pcb_hole_margin; 459 pcb_left_hole_height = pcb_back_support_left_bump_height - pcb_hole_margin * 2; 460 pcb_left_hole_offset_from_centre = -(pcb_support_offset_from_centre + 461 pcb_back_support_width / 2 - pcb_hole_width / 2); 462 463 pcb_right_hole_offset = pcb_back_support_right_bump_offset_from_bottom + pcb_hole_margin; 464 pcb_right_hole_height = pcb_back_support_right_bump_height - pcb_hole_margin * 2; 465 pcb_right_hole_offset_from_centre = -pcb_left_hole_offset_from_centre; 466 467 pcb_hole_depth = pcb_depth + 2 * pcb_hole_extra_depth; 468 pcb_hole_start_depth = edge_connector_cutout_back_depth + pcb_hole_extra_depth; 469 470 wide_pcb_width = 138.0; wide_pcb_height = pcb_height; wide_pcb_depth = pcb_depth; 471 wide_pcb_hole_depth = pcb_hole_depth; 472 wide_pcb_hole_start_depth = pcb_hole_start_depth; 473 474 wide_pcb_lug_hole_radius = 4.0; 475 476 /* An example feature for use with PCB testing. */ 477 478 feature_width = 15.0; feature_depth = 7.0; feature_height = 40.0; 479 feature_height_offset = 10.0; 480 481 /* Repeated constructs. */ 482 483 module pcb_support(xdir, bump_height, bump_offset) { 484 485 /* 486 Translate the support in the stated direction. 487 Since the support is already justified in the direction, the translation 488 moves the inner edge of the support to alignment with the end of the 489 edge connector cutout and then back by the PCB support margin. 490 */ 491 492 translate([xdir * 493 pcb_support_offset_from_centre, 494 edge_connector_cutout_back_depth, 495 int_payload_lower_extent]) 496 justify(pcb_back_support_width, 497 pcb_back_support_depth, 498 pcb_back_support_height, 499 xdir, 1, 1) 500 union() { 501 502 /* Underlying support strut. */ 503 504 cube([pcb_back_support_width, 505 pcb_back_support_depth, 506 pcb_back_support_height], center = true); 507 508 /* Middle bump. */ 509 510 cube_at(pcb_back_support_bump_width, 511 pcb_back_support_bump_depth, 512 bump_height, 513 0, -1, 1, 514 0, 515 -pcb_back_support_depth / 2, 516 -pcb_back_support_height / 2 + bump_offset); 517 518 /* Top bump. */ 519 520 if (SHORT_PCB) 521 cube_at(pcb_back_support_bump_width, 522 pcb_back_support_bump_depth, 523 pcb_back_support_top_bump_height, 524 0, -1, 1, 525 0, 526 -pcb_back_support_depth / 2, 527 pcb_back_support_height / 2 - 528 pcb_back_support_top_bump_height); 529 } 530 } 531 532 module pcb_lug(xdir) { 533 pcb_lug_explicit(xdir, int_connector_width / 2 - pcb_lug_offset_from_inside, 534 pcb_lug_offset_from_bottom); 535 } 536 537 module pcb_lug_wide(xdir) { 538 pcb_lug_explicit(xdir, int_payload_width / 2 - wide_pcb_lug_offset_from_inside, 539 wide_pcb_lug_offset_from_bottom); 540 pcb_lug_explicit(xdir, int_payload_width / 2 - wide_pcb_lug_offset_from_inside, 541 wide_pcb_height - edge_connector_height - wide_pcb_lug_offset_from_bottom); 542 } 543 544 module pcb_lug_explicit(xdir, pcb_lug_offset_from_centre, pcb_lug_offset_from_bottom) { 545 translate([payload_centre + xdir * pcb_lug_offset_from_centre, 546 back_depth, 547 int_payload_lower_extent + pcb_lug_offset_from_bottom 548 ]) 549 rotate([90, 0, 0]) 550 difference() { 551 552 /* Cylinder with cross. */ 553 554 union() { 555 cylinder(h=pcb_lug_depth, r=pcb_lug_outer_radius); 556 cube_at(pcb_lug_cross_width, 557 pcb_lug_cross_height, pcb_lug_cross_depth, 558 0, 0, 1, 559 0, 0, 0); 560 cube_at(pcb_lug_cross_height, 561 pcb_lug_cross_width, pcb_lug_cross_depth, 562 0, 0, 1, 563 0, 0, 0); 564 } 565 566 /* Hollowed out by a cylinder. */ 567 568 cylinder(h=pcb_lug_depth, r=pcb_lug_inner_radius); 569 570 /* Tapered off for easier connection. */ 571 572 if (ROUND_CONNECTING_EDGES) 573 translate([0, 0, pcb_lug_depth - pcb_lug_ro]) 574 fillet_torus(pcb_lug_outer_radius, pcb_lug_rr); 575 } 576 } 577 578 module pcb_front_lug(xdir) { 579 pcb_front_lug_explicit(xdir, int_connector_width / 2 - pcb_lug_offset_from_inside, 580 pcb_lug_offset_from_bottom); 581 } 582 583 module pcb_front_lug_wide(xdir) { 584 pcb_front_lug_explicit(xdir, int_payload_width / 2 - wide_pcb_lug_offset_from_inside, 585 wide_pcb_lug_offset_from_bottom); 586 pcb_front_lug_explicit(xdir, int_payload_width / 2 - wide_pcb_lug_offset_from_inside, 587 wide_pcb_height - edge_connector_height - wide_pcb_lug_offset_from_bottom); 588 } 589 590 module pcb_front_lug_explicit(xdir, pcb_lug_offset_from_centre, pcb_lug_offset_from_bottom) { 591 translate([payload_centre + xdir * pcb_lug_offset_from_centre, 592 -int_front_depth + pcb_front_lug_depth, 593 int_payload_lower_extent + pcb_lug_offset_from_bottom 594 ]) 595 rotate([90, 0, 0]) 596 difference() { 597 cylinder(h=pcb_front_lug_depth, 598 r=pcb_front_lug_outer_radius); 599 cylinder(h=pcb_front_lug_depth, 600 r=pcb_front_lug_inner_radius); 601 } 602 } 603 604 /* The actual shapes. */ 605 606 module front_piece(front_displacement, front_displacement_together) { 607 if (FRONT) 608 translate([front_displacement, front_displacement_together, 0]) 609 difference() { 610 611 /* The cartridge surfaces. */ 612 613 union() { 614 615 /* Front portion. */ 616 617 if (FRONT_SURFACE) { 618 619 /* Surfaces surrounding the payload. */ 620 621 cube_at(payload_width, front, payload_height, 622 0, -1, 1, 623 payload_centre, -int_front_depth, int_payload_lower_extent); 624 625 cube_at(front_left, front_depth, payload_height, 626 -1, -1, 1, 627 int_payload_left_extent, 0, int_payload_lower_extent); 628 629 cube_at(front_right, front_depth, payload_height, 630 1, -1, 1, 631 int_payload_right_extent, 0, int_payload_lower_extent); 632 633 /* Surfaces surrounding the connector. */ 634 635 cube_at(connector_width, front, connector_height, 636 0, -1, -1, 637 0, -int_front_depth, int_payload_lower_extent); 638 639 cube_at(front_left, front_depth, connector_height, 640 -1, -1, -1, 641 int_connector_left_extent, 0, int_payload_lower_extent); 642 643 cube_at(front_right, front_depth, connector_height, 644 1, -1, -1, 645 int_connector_right_extent, 0, int_payload_lower_extent); 646 647 /* Top surface for the front piece. */ 648 649 if (TOP_SURFACE) 650 cube_at(payload_width, front_depth, top, 651 0, -1, 1, 652 payload_centre, 0, int_payload_upper_extent); 653 } 654 655 difference() { 656 657 /* Floor of cartridge. */ 658 659 if (payload_width > connector_width) { 660 cube_at(payload_width, front_depth, bottom, 661 1, -1, 1, 662 payload_left_extent, 0, lower_extent + int_connector_height); 663 } else { 664 cube_at(int_connector_width, int_front_depth, bottom, 665 0, -1, 1, 666 0, 0, lower_extent + int_connector_height); 667 } 668 669 /* Left cutout. */ 670 671 cube_at(edge_connector_cutout_front_width, 672 edge_connector_cutout_front_depth, 673 bottom, 674 1, -1, 1, 675 int_connector_left_extent, 676 0, 677 lower_extent + int_connector_height); 678 679 /* Right cutout. */ 680 681 cube_at(edge_connector_cutout_front_width, 682 edge_connector_cutout_front_depth, 683 bottom, 684 -1, -1, 1, 685 int_connector_right_extent, 686 0, 687 lower_extent + int_connector_height); 688 } 689 690 /* PCB supports. */ 691 692 if (MODEL == ROM_CARTRIDGE) { 693 cube_at(pcb_front_support_width, 694 pcb_front_support_depth, 695 pcb_front_support_height, 696 -1, -1, 1, 697 -pcb_support_offset_from_centre, 698 0, 699 int_payload_lower_extent); 700 701 cube_at(pcb_front_support_width, 702 pcb_front_support_depth, 703 pcb_front_support_height, 704 1, -1, 1, 705 pcb_support_offset_from_centre, 706 0, 707 int_payload_lower_extent); 708 709 /* Circular "lugs" to hold PCBs in place. */ 710 711 pcb_front_lug(-1); 712 pcb_front_lug(1); 713 } 714 715 if (MODEL == WIDE_CARTRIDGE) { 716 717 pcb_front_lug_wide(-1); 718 pcb_front_lug_wide(1); 719 } 720 } 721 722 /* Label insets. */ 723 724 union() { 725 726 /* Front label. */ 727 728 if (FRONT_LABEL_INSET) 729 translate([front_label_left_extent, -front_depth, 730 lower_extent + front_label_offset_from_bottom]) 731 cube([front_label_width, front_label_depth, 732 front_label_height]); 733 734 /* Top label. See also the back piece. */ 735 736 if (TOP_LABEL_INSET) 737 translate([top_label_left_extent, 738 -front_depth + top_label_offset_from_front, 739 upper_extent - top_label_depth]) 740 cube([top_label_width, top_label_height, 741 top_label_depth]); 742 } 743 744 /* Inner front edge cavity. */ 745 746 translate([inner_front_edge_width / 2, -int_front_depth, lower_extent]) 747 rotate([0, -90, 0]) 748 linear_extrude(height = inner_front_edge_width) 749 polygon([ 750 [-extra, -inner_front_edge_depth], 751 [0, -inner_front_edge_depth], 752 [inner_front_edge_height, 0], 753 [-extra, 0], 754 ]); 755 756 /* Inner grooves for the top and sides of the back portion. */ 757 758 cube_at(inner_top_front_cutout_width, 759 inner_top_front_cutout_depth, 760 inner_top_front_cutout_height, 761 1, -1, 1, 762 int_payload_left_extent, 0, int_payload_upper_extent); 763 764 cube_at(inner_payload_front_cutout_width, 765 inner_payload_front_cutout_depth, 766 inner_payload_front_cutout_height, 767 1, -1, 1, 768 int_payload_right_extent, 0, int_payload_lower_extent); 769 770 cube_at(inner_payload_front_cutout_width, 771 inner_payload_front_cutout_depth, 772 inner_payload_front_cutout_height, 773 -1, -1, 1, 774 int_payload_left_extent, 0, int_payload_lower_extent); 775 776 /* Cutout to accept the back connector sides (or the floor of the back piece). */ 777 778 cube_at(inner_connector_front_cutout_width, 779 BACK_CONNECTOR_SECTION ? inner_connector_front_cutout_depth : edge_connector_cutout_front_depth, 780 BACK_CONNECTOR_SECTION ? inner_connector_front_cutout_height : bottom, 781 1, -1, -1, 782 int_connector_right_extent, 0, int_payload_lower_extent); 783 784 cube_at(inner_connector_front_cutout_width, 785 BACK_CONNECTOR_SECTION ? inner_connector_front_cutout_depth : edge_connector_cutout_front_depth, 786 BACK_CONNECTOR_SECTION ? inner_connector_front_cutout_height : bottom, 787 -1, -1, -1, 788 int_connector_left_extent, 0, int_payload_lower_extent); 789 790 /* Fillets to round off the edges. */ 791 792 union() { 793 if (ROUND_EDGES) { 794 795 /* Top left and right rounding. */ 796 797 translate([payload_left_extent + ro, -front_depth / 2, upper_extent - ro]) 798 rotate([0, 0, 180]) 799 rotate([90, 0, 0]) 800 fillet(rr, front_depth); 801 translate([payload_right_extent - ro, -front_depth / 2, upper_extent - ro]) 802 rotate([90, 0, 0]) 803 fillet(rr, front_depth); 804 805 /* Top front rounding. */ 806 807 translate([payload_centre, -front_depth + ro, upper_extent - ro]) 808 rotate([0, 0, 180]) 809 rotate([0, -90, 0]) 810 fillet(rr, payload_width); 811 812 /* Edge rounding. */ 813 814 translate([payload_right_extent - ro, -front_depth + ro, int_payload_lower_extent - bottom - extra]) 815 rotate([0, 0, 270]) 816 fillet_justified(rr, payload_height + bottom + extra); 817 818 translate([payload_left_extent + ro, -front_depth + ro, int_payload_lower_extent - bottom - extra]) 819 rotate([0, 0, 180]) 820 fillet_justified(rr, payload_height + bottom + extra); 821 822 translate([connector_right_extent - ro, -front_depth + ro, lower_extent]) 823 rotate([0, 0, 270]) 824 fillet_partitioned(rr, connector_height - bottom); 825 826 translate([connector_left_extent + ro, -front_depth + ro, lower_extent]) 827 rotate([0, 0, 180]) 828 fillet_partitioned(rr, connector_height - bottom); 829 } 830 } 831 } 832 } 833 834 module back_piece(back_displacement, back_rotation) { 835 if (BACK) 836 translate([back_displacement, 0, 0]) 837 rotate([0, 0, back_rotation]) { 838 difference() { 839 840 /* The cartridge surfaces. */ 841 842 union() { 843 844 /* Back portion. */ 845 846 if (BACK_SURFACE) { 847 848 /* Surfaces surrounding the payload. */ 849 850 /* Payload section of back surface. */ 851 852 cube_at(payload_width, payload_back, payload_height, 853 0, 1, 1, 854 payload_centre, int_payload_back_depth, int_payload_lower_extent); 855 856 cube_at(back_left, back_depth, payload_height, 857 -1, 1, 1, 858 int_payload_left_extent, 0, int_payload_lower_extent); 859 860 cube_at(back_right, back_depth, payload_height, 861 1, 1, 1, 862 int_payload_right_extent, 0, int_payload_lower_extent); 863 864 /* Surfaces surrounding the connector. */ 865 866 /* Connector section of back surface overlapping the floor. */ 867 868 if (BACK_CONNECTOR_SECTION) { 869 cube_at(connector_width, connector_back, connector_height, 870 0, 1, -1, 871 0, int_connector_back_depth, int_payload_lower_extent); 872 873 cube_at(back_left, back_depth, connector_height, 874 -1, 1, -1, 875 int_connector_left_extent, 0, int_payload_lower_extent); 876 877 cube_at(back_right, back_depth, connector_height, 878 1, 1, -1, 879 int_connector_right_extent, 0, int_payload_lower_extent); 880 } 881 882 /* Top of back piece. */ 883 884 if (TOP_SURFACE) 885 cube_at(payload_width, back_depth, top, 886 0, 1, 1, 887 payload_centre, 0, int_payload_upper_extent); 888 889 /* 890 The extension of the back to connect with the front. Here, the inside 891 edges are rounded. The outside edges are rounded later. 892 893 An extra overlapping measure is employed so that the filleting is 894 continuous between the payload and connector portions. On the inside 895 edges, the connector filleting is extended upwards. 896 */ 897 898 /* Left side of payload. */ 899 900 difference() { 901 cube_at(back_left - groove_depth, groove_width_extra, inner_payload_front_cutout_height, 902 -1, 1, 1, 903 int_payload_left_extent, -groove_width_extra, int_payload_lower_extent); 904 if (ROUND_CONNECTING_EDGES) 905 translate([int_payload_left_extent - groove_ro, -groove_width_extra + groove_ro, 906 int_payload_lower_extent]) 907 rotate([0, 0, -90]) 908 fillet_justified(groove_rr, inner_payload_front_cutout_height); 909 } 910 911 /* Right side of payload. */ 912 913 difference() { 914 cube_at(back_right - groove_depth, groove_width_extra, inner_payload_front_cutout_height, 915 1, 1, 1, 916 int_payload_right_extent, -groove_width_extra, int_payload_lower_extent); 917 if (ROUND_CONNECTING_EDGES) 918 translate([int_payload_right_extent + groove_ro, -groove_width_extra + groove_ro, 919 int_payload_lower_extent]) 920 rotate([0, 0, 180]) 921 fillet_justified(groove_rr, inner_payload_front_cutout_height); 922 } 923 924 if (BACK_CONNECTOR_SECTION) { 925 926 /* Left side of connector (or floor extension). */ 927 928 difference() { 929 cube_at(back_left - groove_depth, groove_width_extra, 930 inner_connector_front_cutout_height, 931 -1, 1, -1, 932 int_connector_left_extent, -groove_width_extra, int_payload_lower_extent); 933 if (ROUND_CONNECTING_EDGES) 934 translate([int_connector_left_extent - groove_ro, 935 -groove_width_extra + groove_ro, 936 lower_extent]) 937 rotate([0, 0, -90]) 938 fillet_partitioned(groove_rr, 939 inner_connector_front_cutout_height + extra); 940 } 941 942 /* Right side of connector (or floor extension). */ 943 944 difference() { 945 cube_at(back_right - groove_depth, groove_width_extra, 946 inner_connector_front_cutout_height, 947 1, 1, -1, 948 int_connector_right_extent, -groove_width_extra, int_payload_lower_extent); 949 if (ROUND_CONNECTING_EDGES) 950 translate([int_connector_right_extent + groove_ro, 951 -groove_width_extra + groove_ro, 952 lower_extent]) 953 rotate([0, 0, 180]) 954 fillet_partitioned(groove_rr, 955 inner_connector_front_cutout_height + extra); 956 } 957 } 958 959 /* Top side. */ 960 961 difference() { 962 cube_at(payload_width - groove_depth * 2, groove_width_extra, top - top_groove_depth, 963 0, 1, 1, 964 payload_centre, -groove_width_extra, int_payload_upper_extent); 965 if (ROUND_CONNECTING_EDGES) 966 translate([payload_centre, -groove_width_extra + groove_ro, 967 int_payload_upper_extent + groove_ro]) 968 rotate([0, 0, 180]) 969 rotate([0, 90, 0]) 970 fillet(groove_rr, payload_width - groove_depth * 2); 971 } 972 } 973 974 difference() { 975 976 /* Floor of cartridge. */ 977 978 if (payload_width > connector_width) { 979 980 difference() { 981 cube_at(payload_width, back_depth, bottom, 982 1, 1, 1, 983 payload_left_extent, 0, lower_extent + int_connector_height); 984 985 /* Cut out the floor to provide a tab. */ 986 987 cube_at(payload_width - connector_width + groove_depth, 988 edge_connector_cutout_front_depth, bottom, 989 1, 1, 1, 990 payload_left_extent, 0, lower_extent + int_connector_height); 991 } 992 993 } else { 994 cube_at(connector_width, back_depth, bottom, 995 0, 1, 1, 996 0, 0, lower_extent + int_connector_height); 997 } 998 999 /* Edge connector cutout. */ 1000 1001 cube_at(edge_connector_cutout_back_width, 1002 edge_connector_cutout_back_depth, 1003 bottom, 1004 0, 1, 1, 1005 0, 0, lower_extent + int_connector_height); 1006 } 1007 1008 /* PCB supports. */ 1009 1010 if (MODEL == ROM_CARTRIDGE) { 1011 pcb_support(-1, pcb_back_support_left_bump_height, 1012 pcb_back_support_left_bump_offset_from_bottom); 1013 pcb_support(1, pcb_back_support_right_bump_height, 1014 pcb_back_support_right_bump_offset_from_bottom); 1015 1016 /* Circular "lugs" to hold PCBs in place. */ 1017 1018 pcb_lug(-1); 1019 pcb_lug(1); 1020 } 1021 1022 if (MODEL == WIDE_CARTRIDGE) { 1023 1024 pcb_lug_wide(1); 1025 pcb_lug_wide(-1); 1026 } 1027 } 1028 1029 /* Label insets. */ 1030 1031 union() { 1032 1033 /* Top label. See also the front piece. */ 1034 1035 if (TOP_LABEL_INSET) 1036 translate([top_label_left_extent, 1037 -front_depth + top_label_offset_from_front, 1038 upper_extent - top_label_depth]) 1039 cube([top_label_width, top_label_height, 1040 top_label_depth]); 1041 } 1042 1043 /* Top and side grooves, positioned in the back portion. */ 1044 1045 union() { 1046 1047 /* 1048 Grooves are separated to permit a discontinuity with the 1049 wide cartridge and for control over the back section. 1050 */ 1051 1052 cube_at(groove_depth, groove_width_normal, payload_height + bottom, 1053 1, 1, -1, 1054 payload_left_extent, 0, upper_extent); 1055 1056 if (BACK_CONNECTOR_SECTION) 1057 cube_at(groove_depth, groove_width_normal, connector_height, 1058 1, 1, 1, 1059 connector_left_extent, 0, lower_extent); 1060 1061 /* Right groove. */ 1062 1063 cube_at(groove_depth, groove_width_normal, height, 1064 -1, 1, 0, 1065 payload_right_extent, 0, 0); 1066 1067 if (BACK_CONNECTOR_SECTION) 1068 cube_at(groove_depth, groove_width_normal, connector_height, 1069 -1, 1, 1, 1070 connector_right_extent, 0, lower_extent); 1071 1072 /* Top grooves. */ 1073 1074 cube_at(payload_width, groove_width_normal, groove_depth, 1075 0, 1, -1, 1076 payload_centre, 0, upper_extent); 1077 1078 cube_at(payload_width, top_groove_width, top_groove_depth, 1079 0, 1, -1, 1080 payload_centre, -groove_width_extra, upper_extent); 1081 } 1082 1083 if (BACK_CONNECTOR_SECTION) { 1084 1085 /* Back cavity. */ 1086 1087 if (BACK_CAVITY) 1088 intersection() { 1089 1090 /* From the bottom upwards. */ 1091 1092 translate([0, back_depth, lower_extent]) 1093 linear_extrude(height = back_cavity_height) 1094 translate([int_connector_left_extent, 0, 0]) 1095 polygon([ 1096 [back_cavity_offset_from_inner_left, 0], 1097 [back_cavity_inner_offset_from_inner_left, 1098 -back_cavity_depth], 1099 [back_cavity_inner_offset_from_inner_left + 1100 back_cavity_inner_width, 1101 -back_cavity_depth], 1102 [back_cavity_offset_from_inner_left + 1103 back_cavity_width, 0] 1104 ]); 1105 1106 /* From left to right. */ 1107 1108 translate([back_cavity_width / 2, back_depth, lower_extent]) 1109 rotate([0, -90, 0]) 1110 linear_extrude(height = back_cavity_width) 1111 polygon([ 1112 [-extra, -back_cavity_depth], 1113 [back_cavity_inner_height, 1114 -back_cavity_depth], 1115 [back_cavity_height, 0], 1116 [-extra, 0] 1117 ]); 1118 } 1119 1120 /* Inner back cavities. */ 1121 1122 translate([0, int_connector_back_depth, lower_extent]) 1123 linear_extrude(height = int_connector_height) 1124 translate([int_connector_left_extent, 0, 0]) 1125 polygon([ 1126 [0, 0], 1127 [inner_back_slope_max_offset, 0], 1128 [inner_back_slope_min_offset, 1129 inner_back_slope_depth], 1130 [0, inner_back_slope_depth] 1131 ]); 1132 1133 translate([0, int_connector_back_depth, lower_extent]) 1134 linear_extrude(height = int_connector_height) 1135 translate([int_connector_right_extent, 0, 0]) 1136 polygon([ 1137 [0, 0], 1138 [-inner_back_slope_max_offset, 0], 1139 [-inner_back_slope_min_offset, 1140 inner_back_slope_depth], 1141 [0, inner_back_slope_depth] 1142 ]); 1143 1144 /* Inner back edge cavity. */ 1145 1146 translate([inner_back_edge_width / 2, 1147 int_connector_back_depth + inner_back_edge_depth, lower_extent]) 1148 rotate([0, -90, 0]) 1149 linear_extrude(height = inner_back_edge_width) 1150 polygon([ 1151 [-extra, -inner_back_edge_depth], 1152 [inner_back_edge_height, -inner_back_edge_depth], 1153 [0, 0], 1154 [-extra, 0] 1155 ]); 1156 } 1157 1158 /* Fillets to round off the edges. */ 1159 1160 union() { 1161 if (ROUND_EDGES) { 1162 1163 /* Top left and right rounding. */ 1164 1165 translate([payload_left_extent + ro, back_depth / 2, upper_extent - ro]) 1166 rotate([0, 0, 180]) 1167 rotate([90, 0, 0]) 1168 fillet(rr, back_depth); 1169 translate([payload_right_extent - ro, back_depth / 2, upper_extent - ro]) 1170 rotate([90, 0, 0]) 1171 fillet(rr, back_depth); 1172 1173 /* Top back rounding. */ 1174 1175 translate([payload_centre, back_depth - ro, upper_extent - ro]) 1176 rotate([0, -90, 0]) 1177 fillet(rr, payload_width); 1178 1179 /* Outer edge rounding. */ 1180 1181 translate([payload_right_extent - ro, back_depth - ro, int_payload_lower_extent - bottom - extra]) 1182 fillet_justified(rr, payload_height + bottom + extra); 1183 1184 translate([payload_left_extent + ro, back_depth - ro, int_payload_lower_extent - bottom - extra]) 1185 rotate([0, 0, 90]) 1186 fillet_justified(rr, payload_height + bottom + extra); 1187 1188 if (BACK_CONNECTOR_SECTION) { 1189 translate([connector_right_extent - ro, back_depth - ro, lower_extent]) 1190 fillet_partitioned(rr, connector_height - bottom); 1191 1192 translate([connector_left_extent + ro, back_depth - ro, lower_extent]) 1193 rotate([0, 0, 90]) 1194 fillet_partitioned(rr, connector_height - bottom); 1195 } 1196 } 1197 1198 if (ROUND_CONNECTING_EDGES) { 1199 1200 /* 1201 Outer edge rounding of the back extension. This is done as a 1202 separate removal operation rather than occurring when creating the 1203 extension in order to ensure that the edges are actually rounded. 1204 1205 An extra overlapping measure is employed so that the filleting is 1206 continuous between the payload and connector portions. On the outside 1207 edges, the payload filleting is extended downwards. 1208 */ 1209 1210 translate([payload_left_extent + groove_depth + groove_ro, -groove_width_extra + groove_ro, 1211 int_payload_lower_extent - extra]) 1212 rotate([0, 0, 180]) 1213 fillet_justified(groove_rr, inner_payload_front_cutout_height + extra); 1214 1215 translate([payload_right_extent - groove_depth - groove_ro, -groove_width_extra + groove_ro, 1216 int_payload_lower_extent - extra]) 1217 rotate([0, 0, -90]) 1218 fillet_justified(groove_rr, inner_payload_front_cutout_height + extra); 1219 1220 /* Sides of connector. */ 1221 1222 translate([connector_left_extent + groove_depth + groove_ro, -groove_width_extra + groove_ro, 1223 lower_extent]) 1224 rotate([0, 0, 180]) 1225 fillet_partitioned(groove_rr, inner_connector_front_cutout_height); 1226 1227 translate([connector_right_extent - groove_depth - groove_ro, -groove_width_extra + groove_ro, 1228 lower_extent]) 1229 rotate([0, 0, -90]) 1230 fillet_partitioned(groove_rr, inner_connector_front_cutout_height); 1231 1232 /* Top of payload. */ 1233 1234 translate([payload_centre, -groove_width_extra + groove_ro, 1235 int_payload_upper_extent + inner_top_front_cutout_height - groove_ro]) 1236 rotate([0, 0, 180]) 1237 rotate([0, -90, 0]) 1238 fillet(groove_rr, payload_width - groove_depth * 2); 1239 } 1240 } 1241 } 1242 1243 /* PCBs for checking. */ 1244 1245 if (PCB) if (MODEL == ROM_CARTRIDGE) { 1246 translate([0, 0, int_payload_lower_extent]) 1247 difference() { 1248 1249 /* Mock PCB. */ 1250 1251 union() { 1252 cube_at(pcb_width, pcb_depth, 1253 pcb_height - edge_connector_height, 1254 0, -1, 1, 1255 0, edge_connector_cutout_back_depth, 0); 1256 cube_at(edge_connector_width, pcb_depth, 1257 edge_connector_height, 1258 0, -1, -1, 1259 0, edge_connector_cutout_back_depth, 0); 1260 1261 /* Feature. */ 1262 1263 cube_at(feature_width, feature_depth, feature_height, 1264 0, 1, 1, 1265 0, edge_connector_cutout_back_depth, feature_height_offset); 1266 } 1267 1268 /* Holes for mounting. */ 1269 1270 union() { 1271 cube_at(pcb_hole_width, pcb_hole_depth, pcb_left_hole_height, 1272 -1, -1, 1, 1273 pcb_left_hole_offset_from_centre, pcb_hole_start_depth, 1274 pcb_left_hole_offset); 1275 translate([pcb_left_hole_offset_from_centre - 1276 pcb_hole_width / 2, pcb_hole_start_depth, pcb_left_hole_offset]) 1277 rotate([90, 0, 0]) 1278 cylinder(h=pcb_hole_depth, r=pcb_hole_width / 2); 1279 translate([pcb_left_hole_offset_from_centre - 1280 pcb_hole_width / 2, pcb_hole_start_depth, 1281 pcb_left_hole_offset + pcb_left_hole_height]) 1282 rotate([90, 0, 0]) 1283 cylinder(h=pcb_hole_depth, r=pcb_hole_width / 2); 1284 } 1285 1286 union() { 1287 cube_at(pcb_hole_width, pcb_hole_depth, pcb_right_hole_height, 1288 1, -1, 1, 1289 pcb_right_hole_offset_from_centre, pcb_hole_start_depth, 1290 pcb_right_hole_offset); 1291 translate([pcb_right_hole_offset_from_centre + 1292 pcb_hole_width / 2, pcb_hole_start_depth, pcb_right_hole_offset]) 1293 rotate([90, 0, 0]) 1294 cylinder(h=pcb_hole_depth, r=pcb_hole_width / 2); 1295 translate([pcb_right_hole_offset_from_centre + 1296 pcb_hole_width / 2, pcb_hole_start_depth, 1297 pcb_right_hole_offset + pcb_right_hole_height]) 1298 rotate([90, 0, 0]) 1299 cylinder(h=pcb_hole_depth, r=pcb_hole_width / 2); 1300 } 1301 1302 /* Holes for lugs. */ 1303 1304 translate([ 1305 int_connector_left_extent + pcb_lug_offset_from_inside, 1306 pcb_hole_start_depth, pcb_lug_offset_from_bottom]) 1307 rotate([90, 0, 0]) 1308 cylinder(h=pcb_hole_depth, r=pcb_lug_hole_radius); 1309 1310 translate([ 1311 int_connector_right_extent - pcb_lug_offset_from_inside, 1312 pcb_hole_start_depth, pcb_lug_offset_from_bottom]) 1313 rotate([90, 0, 0]) 1314 cylinder(h=pcb_hole_depth, r=pcb_lug_hole_radius); 1315 } 1316 } 1317 1318 if (PCB) if (MODEL == WIDE_CARTRIDGE) { 1319 translate([0, 0, int_payload_lower_extent]) 1320 difference() { 1321 1322 /* Mock PCB. */ 1323 1324 union() { 1325 cube_at(wide_pcb_width, wide_pcb_depth, 1326 wide_pcb_height - edge_connector_height, 1327 0, -1, 1, 1328 payload_centre, edge_connector_cutout_back_depth, 0); 1329 cube_at(edge_connector_width, wide_pcb_depth, 1330 edge_connector_height, 1331 0, -1, -1, 1332 0, edge_connector_cutout_back_depth, 0); 1333 1334 /* Feature. */ 1335 1336 cube_at(feature_width, feature_depth, feature_height, 1337 0, 1, 1, 1338 0, edge_connector_cutout_back_depth, feature_height_offset); 1339 } 1340 1341 /* Holes for lugs. */ 1342 1343 translate([ 1344 payload_centre + int_payload_width / 2 - wide_pcb_lug_offset_from_inside , 1345 wide_pcb_hole_start_depth, 1346 wide_pcb_height - edge_connector_height - wide_pcb_lug_offset_from_bottom]) 1347 rotate([90, 0, 0]) 1348 cylinder(h=wide_pcb_hole_depth, r=wide_pcb_lug_hole_radius); 1349 1350 translate([ 1351 payload_centre - int_payload_width / 2 + wide_pcb_lug_offset_from_inside , 1352 wide_pcb_hole_start_depth, 1353 wide_pcb_height - edge_connector_height - wide_pcb_lug_offset_from_bottom]) 1354 rotate([90, 0, 0]) 1355 cylinder(h=wide_pcb_hole_depth, r=wide_pcb_lug_hole_radius); 1356 1357 translate([ 1358 payload_centre + int_payload_width / 2 - wide_pcb_lug_offset_from_inside , 1359 wide_pcb_hole_start_depth, 1360 wide_pcb_lug_offset_from_bottom]) 1361 rotate([90, 0, 0]) 1362 cylinder(h=wide_pcb_hole_depth, r=wide_pcb_lug_hole_radius); 1363 1364 translate([ 1365 payload_centre - int_payload_width / 2 + wide_pcb_lug_offset_from_inside , 1366 wide_pcb_hole_start_depth, 1367 wide_pcb_lug_offset_from_bottom]) 1368 rotate([90, 0, 0]) 1369 cylinder(h=wide_pcb_hole_depth, r=wide_pcb_lug_hole_radius); 1370 } 1371 } 1372 } 1373 } 1374 1375 /* 1376 Place the back piece next to the front, with the internals facing out 1377 the same way, if APART is defined. 1378 */ 1379 1380 front_displacement_together = CLOSED ? front_back_overlap : front_back_overlap - SPACE_APART; 1381 front_displacement = APART ? -connector_width * 0.6 : 0; 1382 back_displacement = APART ? connector_width * 0.6 : 0; 1383 back_rotation = APART ? 180 : 0; 1384 1385 if (INTERSECT) { 1386 intersection() { 1387 front_piece(0, front_displacement_together); 1388 back_piece(0, 0); 1389 } 1390 } else { 1391 front_piece(front_displacement, front_displacement_together); 1392 back_piece(back_displacement, back_rotation); 1393 } 1394 } 1395 1396 cartridge();