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 /* Cutout to accept the back connector sides (or the floor of the back piece). */ 769 770 cube_at(inner_connector_front_cutout_width, 771 inner_connector_front_cutout_depth, 772 BACK_CONNECTOR_SECTION ? inner_connector_front_cutout_height : bottom, 773 1, -1, -1, 774 int_connector_width / 2, 0, int_payload_lower_extent); 775 776 cube_at(inner_connector_front_cutout_width, 777 inner_connector_front_cutout_depth, 778 BACK_CONNECTOR_SECTION ? inner_connector_front_cutout_height : bottom, 779 -1, -1, -1, 780 -int_connector_width / 2, 0, int_payload_lower_extent); 781 782 /* Fillets to round off the edges. */ 783 784 union() { 785 if (ROUND_EDGES) { 786 787 /* Top left and right rounding. */ 788 789 translate([payload_left_extent + ro, -front_depth / 2, upper_extent - ro]) 790 rotate([0, 0, 180]) 791 rotate([90, 0, 0]) 792 fillet(rr, front_depth); 793 translate([payload_right_extent - ro, -front_depth / 2, upper_extent - ro]) 794 rotate([90, 0, 0]) 795 fillet(rr, front_depth); 796 797 /* Top front rounding. */ 798 799 translate([payload_centre, -front_depth + ro, upper_extent - ro]) 800 rotate([0, 0, 180]) 801 rotate([0, -90, 0]) 802 fillet(rr, payload_width); 803 804 /* Edge rounding. */ 805 806 translate([payload_right_extent - ro, -front_depth + ro, int_payload_lower_extent - bottom - extra]) 807 rotate([0, 0, 270]) 808 fillet_justified(rr, payload_height + bottom + extra); 809 810 translate([payload_left_extent + ro, -front_depth + ro, int_payload_lower_extent - bottom - extra]) 811 rotate([0, 0, 180]) 812 fillet_justified(rr, payload_height + bottom + extra); 813 814 translate([connector_width / 2 - ro, -front_depth + ro, lower_extent]) 815 rotate([0, 0, 270]) 816 fillet_partitioned(rr, connector_height - bottom); 817 818 translate([-connector_width / 2 + ro, -front_depth + ro, lower_extent]) 819 rotate([0, 0, 180]) 820 fillet_partitioned(rr, connector_height - bottom); 821 } 822 } 823 } 824 } 825 826 module back_piece(back_displacement, back_rotation) { 827 if (BACK) 828 translate([back_displacement, 0, 0]) 829 rotate([0, 0, back_rotation]) { 830 difference() { 831 832 /* The cartridge surfaces. */ 833 834 union() { 835 836 /* Back portion. */ 837 838 if (BACK_SURFACE) { 839 840 /* Surfaces surrounding the payload. */ 841 842 /* Payload section of back surface. */ 843 844 cube_at(payload_width, payload_back, payload_height, 845 0, 1, 1, 846 payload_centre, int_payload_back_depth, int_payload_lower_extent); 847 848 cube_at(back_left, back_depth, payload_height, 849 -1, 1, 1, 850 int_payload_left_extent, 0, int_payload_lower_extent); 851 852 cube_at(back_right, back_depth, payload_height, 853 1, 1, 1, 854 int_payload_right_extent, 0, int_payload_lower_extent); 855 856 /* Surfaces surrounding the connector. */ 857 858 /* Connector section of back surface overlapping the floor. */ 859 860 if (BACK_CONNECTOR_SECTION) { 861 cube_at(connector_width, connector_back, connector_height, 862 0, 1, -1, 863 0, int_connector_back_depth, int_payload_lower_extent); 864 865 cube_at(back_left, back_depth, connector_height, 866 -1, 1, -1, 867 -int_connector_width / 2, 0, int_payload_lower_extent); 868 869 cube_at(back_right, back_depth, connector_height, 870 1, 1, -1, 871 int_connector_width / 2, 0, int_payload_lower_extent); 872 } 873 874 /* Top of back piece. */ 875 876 if (TOP_SURFACE) 877 cube_at(payload_width, back_depth, top, 878 0, 1, 1, 879 payload_centre, 0, int_payload_upper_extent); 880 881 /* 882 The extension of the back to connect with the front. Here, the inside 883 edges are rounded. The outside edges are rounded later. 884 885 An extra overlapping measure is employed so that the filleting is 886 continuous between the payload and connector portions. On the inside 887 edges, the connector filleting is extended upwards. 888 */ 889 890 /* Left side of payload. */ 891 892 difference() { 893 cube_at(back_left - groove_depth, groove_width_extra, inner_payload_front_cutout_height, 894 -1, 1, 1, 895 int_payload_left_extent, -groove_width_extra, int_payload_lower_extent); 896 if (ROUND_CONNECTING_EDGES) 897 translate([int_payload_left_extent - groove_ro, -groove_width_extra + groove_ro, 898 int_payload_lower_extent]) 899 rotate([0, 0, -90]) 900 fillet_justified(groove_rr, inner_payload_front_cutout_height); 901 } 902 903 /* Right side of payload. */ 904 905 difference() { 906 cube_at(back_right - groove_depth, groove_width_extra, inner_payload_front_cutout_height, 907 1, 1, 1, 908 int_payload_right_extent, -groove_width_extra, int_payload_lower_extent); 909 if (ROUND_CONNECTING_EDGES) 910 translate([int_payload_right_extent + groove_ro, -groove_width_extra + groove_ro, 911 int_payload_lower_extent]) 912 rotate([0, 0, 180]) 913 fillet_justified(groove_rr, inner_payload_front_cutout_height); 914 } 915 916 if (BACK_CONNECTOR_SECTION) { 917 918 /* Left side of connector. */ 919 920 difference() { 921 cube_at(back_left - groove_depth, groove_width_extra, 922 inner_connector_front_cutout_height, 923 -1, 1, -1, 924 -int_connector_width / 2, -groove_width_extra, int_payload_lower_extent); 925 if (ROUND_CONNECTING_EDGES) 926 translate([-int_connector_width / 2 - groove_ro, 927 -groove_width_extra + groove_ro, 928 lower_extent]) 929 rotate([0, 0, -90]) 930 fillet_partitioned(groove_rr, 931 inner_connector_front_cutout_height + extra); 932 } 933 934 /* Right side of connector. */ 935 936 difference() { 937 cube_at(back_right - groove_depth, groove_width_extra, 938 inner_connector_front_cutout_height, 939 1, 1, -1, 940 int_connector_width / 2, -groove_width_extra, int_payload_lower_extent); 941 if (ROUND_CONNECTING_EDGES) 942 translate([int_connector_width / 2 + groove_ro, 943 -groove_width_extra + groove_ro, 944 lower_extent]) 945 rotate([0, 0, 180]) 946 fillet_partitioned(groove_rr, 947 inner_connector_front_cutout_height + extra); 948 } 949 } 950 951 /* Top side. */ 952 953 difference() { 954 cube_at(payload_width - groove_depth * 2, groove_width_extra, top - top_groove_depth, 955 0, 1, 1, 956 payload_centre, -groove_width_extra, int_payload_upper_extent); 957 if (ROUND_CONNECTING_EDGES) 958 translate([payload_centre, -groove_width_extra + groove_ro, 959 int_payload_upper_extent + groove_ro]) 960 rotate([0, 0, 180]) 961 rotate([0, 90, 0]) 962 fillet(groove_rr, payload_width - groove_depth * 2); 963 } 964 } 965 966 difference() { 967 968 /* Floor of cartridge. */ 969 970 cube_at(connector_width, back_depth, bottom, 971 0, 1, 1, 972 0, 0, lower_extent + int_connector_height); 973 974 /* Edge connector cutout. */ 975 976 cube_at(edge_connector_cutout_back_width, 977 edge_connector_cutout_back_depth, 978 bottom, 979 0, 1, 1, 980 0, 0, lower_extent + int_connector_height); 981 } 982 983 /* Extended floor. */ 984 985 if (payload_width > connector_width) { 986 987 difference() { 988 989 cube_at(payload_width - connector_width, back_depth, bottom, 990 1, 1, 1, 991 payload_left_extent, 0, lower_extent + int_connector_height); 992 993 cube_at(payload_width - connector_width, edge_connector_cutout_front_depth, bottom, 994 1, 1, 1, 995 payload_left_extent, 0, lower_extent + int_connector_height); 996 } 997 } 998 999 /* PCB supports. */ 1000 1001 if (MODEL == ROM_CARTRIDGE) { 1002 pcb_support(-1, pcb_back_support_left_bump_height, 1003 pcb_back_support_left_bump_offset_from_bottom); 1004 pcb_support(1, pcb_back_support_right_bump_height, 1005 pcb_back_support_right_bump_offset_from_bottom); 1006 1007 /* Circular "lugs" to hold PCBs in place. */ 1008 1009 pcb_lug(-1); 1010 pcb_lug(1); 1011 } 1012 1013 if (MODEL == WIDE_CARTRIDGE) { 1014 1015 pcb_lug_wide(1); 1016 pcb_lug_wide(-1); 1017 } 1018 } 1019 1020 /* Label insets. */ 1021 1022 union() { 1023 1024 /* Top label. See also the front piece. */ 1025 1026 if (TOP_LABEL_INSET) 1027 translate([top_label_left_extent, 1028 -front_depth + top_label_offset_from_front, 1029 upper_extent - top_label_depth]) 1030 cube([top_label_width, top_label_height, 1031 top_label_depth]); 1032 } 1033 1034 /* Top and side grooves, positioned in the back portion. */ 1035 1036 union() { 1037 1038 /* Left groove. */ 1039 1040 cube_at(groove_depth, groove_width_normal, height, 1041 1, 1, 0, 1042 payload_left_extent, 0, 0); 1043 1044 /* Right groove. */ 1045 1046 cube_at(groove_depth, groove_width_normal, height, 1047 -1, 1, 0, 1048 payload_right_extent, 0, 0); 1049 1050 /* Top grooves. */ 1051 1052 cube_at(payload_width, groove_width_normal, groove_depth, 1053 0, 1, -1, 1054 payload_centre, 0, upper_extent); 1055 1056 cube_at(payload_width, top_groove_width, top_groove_depth, 1057 0, 1, -1, 1058 payload_centre, -groove_width_extra, upper_extent); 1059 } 1060 1061 if (BACK_CONNECTOR_SECTION) { 1062 1063 /* Back cavity. */ 1064 1065 if (BACK_CAVITY) 1066 intersection() { 1067 1068 /* From the bottom upwards. */ 1069 1070 translate([0, back_depth, lower_extent]) 1071 linear_extrude(height = back_cavity_height) 1072 translate([-int_connector_width / 2, 0, 0]) 1073 polygon([ 1074 [back_cavity_offset_from_inner_left, 0], 1075 [back_cavity_inner_offset_from_inner_left, 1076 -back_cavity_depth], 1077 [back_cavity_inner_offset_from_inner_left + 1078 back_cavity_inner_width, 1079 -back_cavity_depth], 1080 [back_cavity_offset_from_inner_left + 1081 back_cavity_width, 0] 1082 ]); 1083 1084 /* From left to right. */ 1085 1086 translate([back_cavity_width / 2, back_depth, lower_extent]) 1087 rotate([0, -90, 0]) 1088 linear_extrude(height = back_cavity_width) 1089 polygon([ 1090 [-extra, -back_cavity_depth], 1091 [back_cavity_inner_height, 1092 -back_cavity_depth], 1093 [back_cavity_height, 0], 1094 [-extra, 0] 1095 ]); 1096 } 1097 1098 /* Inner back cavities. */ 1099 1100 translate([0, int_connector_back_depth, lower_extent]) 1101 linear_extrude(height = int_connector_height) 1102 translate([-int_connector_width / 2, 0, 0]) 1103 polygon([ 1104 [0, 0], 1105 [inner_back_slope_max_offset, 0], 1106 [inner_back_slope_min_offset, 1107 inner_back_slope_depth], 1108 [0, inner_back_slope_depth] 1109 ]); 1110 1111 translate([0, int_connector_back_depth, lower_extent]) 1112 linear_extrude(height = int_connector_height) 1113 translate([int_connector_width / 2, 0, 0]) 1114 polygon([ 1115 [0, 0], 1116 [-inner_back_slope_max_offset, 0], 1117 [-inner_back_slope_min_offset, 1118 inner_back_slope_depth], 1119 [0, inner_back_slope_depth] 1120 ]); 1121 1122 /* Inner back edge cavity. */ 1123 1124 translate([inner_back_edge_width / 2, 1125 int_connector_back_depth + inner_back_edge_depth, lower_extent]) 1126 rotate([0, -90, 0]) 1127 linear_extrude(height = inner_back_edge_width) 1128 polygon([ 1129 [-extra, -inner_back_edge_depth], 1130 [inner_back_edge_height, -inner_back_edge_depth], 1131 [0, 0], 1132 [-extra, 0] 1133 ]); 1134 } 1135 1136 /* Fillets to round off the edges. */ 1137 1138 union() { 1139 if (ROUND_EDGES) { 1140 1141 /* Top left and right rounding. */ 1142 1143 translate([payload_left_extent + ro, back_depth / 2, upper_extent - ro]) 1144 rotate([0, 0, 180]) 1145 rotate([90, 0, 0]) 1146 fillet(rr, back_depth); 1147 translate([payload_right_extent - ro, back_depth / 2, upper_extent - ro]) 1148 rotate([90, 0, 0]) 1149 fillet(rr, back_depth); 1150 1151 /* Top back rounding. */ 1152 1153 translate([payload_centre, back_depth - ro, upper_extent - ro]) 1154 rotate([0, -90, 0]) 1155 fillet(rr, payload_width); 1156 1157 /* Outer edge rounding. */ 1158 1159 translate([payload_right_extent - ro, back_depth - ro, int_payload_lower_extent - bottom - extra]) 1160 fillet_justified(rr, payload_height + bottom + extra); 1161 1162 translate([payload_left_extent + ro, back_depth - ro, int_payload_lower_extent - bottom - extra]) 1163 rotate([0, 0, 90]) 1164 fillet_justified(rr, payload_height + bottom + extra); 1165 1166 if (BACK_CONNECTOR_SECTION) { 1167 translate([connector_width / 2 - ro, back_depth - ro, lower_extent]) 1168 fillet_partitioned(rr, connector_height - bottom); 1169 1170 translate([-connector_width / 2 + ro, back_depth - ro, lower_extent]) 1171 rotate([0, 0, 90]) 1172 fillet_partitioned(rr, connector_height - bottom); 1173 } 1174 } 1175 1176 if (ROUND_CONNECTING_EDGES) { 1177 1178 /* 1179 Outer edge rounding of the back extension. This is done as a 1180 separate removal operation rather than occurring when creating the 1181 extension in order to ensure that the edges are actually rounded. 1182 1183 An extra overlapping measure is employed so that the filleting is 1184 continuous between the payload and connector portions. On the outside 1185 edges, the payload filleting is extended downwards. 1186 */ 1187 1188 translate([payload_left_extent + groove_depth + groove_ro, -groove_width_extra + groove_ro, 1189 int_payload_lower_extent - extra]) 1190 rotate([0, 0, 180]) 1191 fillet_justified(groove_rr, inner_payload_front_cutout_height + extra); 1192 1193 translate([payload_right_extent - groove_depth - groove_ro, -groove_width_extra + groove_ro, 1194 int_payload_lower_extent - extra]) 1195 rotate([0, 0, -90]) 1196 fillet_justified(groove_rr, inner_payload_front_cutout_height + extra); 1197 1198 /* Sides of connector. */ 1199 1200 translate([-connector_width / 2 + groove_depth + groove_ro, -groove_width_extra + groove_ro, 1201 lower_extent]) 1202 rotate([0, 0, 180]) 1203 fillet_partitioned(groove_rr, inner_connector_front_cutout_height); 1204 1205 translate([connector_width / 2 - groove_depth - groove_ro, -groove_width_extra + groove_ro, 1206 lower_extent]) 1207 rotate([0, 0, -90]) 1208 fillet_partitioned(groove_rr, inner_connector_front_cutout_height); 1209 1210 /* Top of payload. */ 1211 1212 translate([payload_centre, -groove_width_extra + groove_ro, 1213 int_payload_upper_extent + inner_top_front_cutout_height - groove_ro]) 1214 rotate([0, 0, 180]) 1215 rotate([0, -90, 0]) 1216 fillet(groove_rr, payload_width - groove_depth * 2); 1217 } 1218 } 1219 } 1220 1221 /* PCBs for checking. */ 1222 1223 if (PCB) if (MODEL == ROM_CARTRIDGE) { 1224 translate([0, 0, int_payload_lower_extent]) 1225 difference() { 1226 1227 /* Mock PCB. */ 1228 1229 union() { 1230 cube_at(pcb_width, pcb_depth, 1231 pcb_height - edge_connector_height, 1232 0, -1, 1, 1233 0, edge_connector_cutout_back_depth, 0); 1234 cube_at(edge_connector_width, pcb_depth, 1235 edge_connector_height, 1236 0, -1, -1, 1237 0, edge_connector_cutout_back_depth, 0); 1238 1239 /* Feature. */ 1240 1241 cube_at(feature_width, feature_depth, feature_height, 1242 0, 1, 1, 1243 0, edge_connector_cutout_back_depth, feature_height_offset); 1244 } 1245 1246 /* Holes for mounting. */ 1247 1248 union() { 1249 cube_at(pcb_hole_width, pcb_hole_depth, pcb_left_hole_height, 1250 -1, -1, 1, 1251 pcb_left_hole_offset_from_centre, pcb_hole_start_depth, 1252 pcb_left_hole_offset); 1253 translate([pcb_left_hole_offset_from_centre - 1254 pcb_hole_width / 2, pcb_hole_start_depth, pcb_left_hole_offset]) 1255 rotate([90, 0, 0]) 1256 cylinder(h=pcb_hole_depth, r=pcb_hole_width / 2); 1257 translate([pcb_left_hole_offset_from_centre - 1258 pcb_hole_width / 2, pcb_hole_start_depth, 1259 pcb_left_hole_offset + pcb_left_hole_height]) 1260 rotate([90, 0, 0]) 1261 cylinder(h=pcb_hole_depth, r=pcb_hole_width / 2); 1262 } 1263 1264 union() { 1265 cube_at(pcb_hole_width, pcb_hole_depth, pcb_right_hole_height, 1266 1, -1, 1, 1267 pcb_right_hole_offset_from_centre, pcb_hole_start_depth, 1268 pcb_right_hole_offset); 1269 translate([pcb_right_hole_offset_from_centre + 1270 pcb_hole_width / 2, pcb_hole_start_depth, pcb_right_hole_offset]) 1271 rotate([90, 0, 0]) 1272 cylinder(h=pcb_hole_depth, r=pcb_hole_width / 2); 1273 translate([pcb_right_hole_offset_from_centre + 1274 pcb_hole_width / 2, pcb_hole_start_depth, 1275 pcb_right_hole_offset + pcb_right_hole_height]) 1276 rotate([90, 0, 0]) 1277 cylinder(h=pcb_hole_depth, r=pcb_hole_width / 2); 1278 } 1279 1280 /* Holes for lugs. */ 1281 1282 translate([ 1283 -int_connector_width / 2 + pcb_lug_offset_from_inside, 1284 pcb_hole_start_depth, pcb_lug_offset_from_bottom]) 1285 rotate([90, 0, 0]) 1286 cylinder(h=pcb_hole_depth, r=pcb_lug_hole_radius); 1287 1288 translate([ 1289 int_connector_width / 2 - pcb_lug_offset_from_inside, 1290 pcb_hole_start_depth, pcb_lug_offset_from_bottom]) 1291 rotate([90, 0, 0]) 1292 cylinder(h=pcb_hole_depth, r=pcb_lug_hole_radius); 1293 } 1294 } 1295 1296 if (PCB) if (MODEL == WIDE_CARTRIDGE) { 1297 translate([0, 0, int_payload_lower_extent]) 1298 difference() { 1299 1300 /* Mock PCB. */ 1301 1302 union() { 1303 cube_at(wide_pcb_width, wide_pcb_depth, 1304 wide_pcb_height - edge_connector_height, 1305 0, -1, 1, 1306 payload_centre, edge_connector_cutout_back_depth, 0); 1307 cube_at(edge_connector_width, wide_pcb_depth, 1308 edge_connector_height, 1309 0, -1, -1, 1310 0, edge_connector_cutout_back_depth, 0); 1311 1312 /* Feature. */ 1313 1314 cube_at(feature_width, feature_depth, feature_height, 1315 0, 1, 1, 1316 0, edge_connector_cutout_back_depth, feature_height_offset); 1317 } 1318 1319 /* Holes for lugs. */ 1320 1321 translate([ 1322 payload_centre + int_payload_width / 2 - wide_pcb_lug_offset_from_inside , 1323 wide_pcb_hole_start_depth, 1324 wide_pcb_height - edge_connector_height - wide_pcb_lug_offset_from_bottom]) 1325 rotate([90, 0, 0]) 1326 cylinder(h=wide_pcb_hole_depth, r=wide_pcb_lug_hole_radius); 1327 1328 translate([ 1329 payload_centre - int_payload_width / 2 + wide_pcb_lug_offset_from_inside , 1330 wide_pcb_hole_start_depth, 1331 wide_pcb_height - edge_connector_height - wide_pcb_lug_offset_from_bottom]) 1332 rotate([90, 0, 0]) 1333 cylinder(h=wide_pcb_hole_depth, r=wide_pcb_lug_hole_radius); 1334 1335 translate([ 1336 payload_centre + int_payload_width / 2 - wide_pcb_lug_offset_from_inside , 1337 wide_pcb_hole_start_depth, 1338 wide_pcb_lug_offset_from_bottom]) 1339 rotate([90, 0, 0]) 1340 cylinder(h=wide_pcb_hole_depth, r=wide_pcb_lug_hole_radius); 1341 1342 translate([ 1343 payload_centre - int_payload_width / 2 + wide_pcb_lug_offset_from_inside , 1344 wide_pcb_hole_start_depth, 1345 wide_pcb_lug_offset_from_bottom]) 1346 rotate([90, 0, 0]) 1347 cylinder(h=wide_pcb_hole_depth, r=wide_pcb_lug_hole_radius); 1348 } 1349 } 1350 } 1351 } 1352 1353 /* 1354 Place the back piece next to the front, with the internals facing out 1355 the same way, if APART is defined. 1356 */ 1357 1358 front_displacement_together = CLOSED ? front_back_overlap : 0; 1359 front_displacement = APART ? -connector_width * 0.6 : 0; 1360 back_displacement = APART ? connector_width * 0.6 : 0; 1361 back_rotation = APART ? 180 : 0; 1362 1363 if (INTERSECT) { 1364 intersection() { 1365 front_piece(0, front_displacement_together); 1366 back_piece(0, 0); 1367 } 1368 } else { 1369 front_piece(front_displacement, front_displacement_together); 1370 back_piece(back_displacement, back_rotation); 1371 } 1372 } 1373 1374 cartridge();