AcornElectron

cartridge.scad

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