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