
Now that my terminal works, it’s time to put it into a nice enclosure. And what better enclosure than a replica of the DEC VT100 terminal? After all, this is the terminal that introduced the famous ANSI terminal codes which are still in use today.
After a bit of searching I found useful documentation giving me the dimensions of a DEC VT100 terminal. On Aliexpress I found a nice 8" LCD display in a retro 4:3 ratio and with an VGA interface board. The dimensions of this 8" display then dictated the scaling factor which turned out to be 60%.
Then it was time to start up openSCAD and draw the shapes for the panels and machine them, glue everything together, lots of sanding, applying a lick of paint and then put everything inside.
Since there was plenty of space inside, I decided to put my CP/M computer inside as well so that the DEC VT100 replica would become a stand alone unit running [of course] CP/M.
The end result
Construction photo’s
openSCAD code
Front panel
3D view
$fs=0.3;
//$fn=60;
LCDpanelRounding = 1.5;
InsetRounding = 1.5;
CutOutRadius = 10;
CutOutInset = 10;
CaseRounding = 6;
VT100_Outline();
VT100FacePoints = [
[ 0, 0, 5.1], //0
[ 274, 0, 5.1], //1
[ 274, 18, 5.1], //2
[ 0, 18, 5.1], //3
[ 4.5, 0, 169 + 5.1 -5], //4
[(274 - 4.5), 0, 169 + 5.1 -5], //5
[(274 - 4.5), 18, 169 + 5.1], //6
[ 4.5, 18, 169 + 5.1] //7
];
VT100FaceFaces = [
[0,1,2,3], // bottom
[4,5,1,0], // front
[7,6,5,4], // top
[5,6,2,1], // right
[6,7,3,2], // back
[7,4,0,3] // left
];
module VT100_Outline()
{
difference()
{
VT100_Face();
VT100_FrontCutOut();
VT100_TopCutOut();
VT100_LcdFront();
VT100_LcdPanelCutOut();
VT100_ChinFaceDivider();
}
VT100_Chin();
}
module VT100_Face()
{
hull()
{
polyhedron(VT100FacePoints, VT100FaceFaces);
difference()
{
translate([4.5, CaseRounding, 168])
rotate([0, 90, 0])
cylinder(h=(274 - (2*4.5)), r=CaseRounding);
translate([4.5, 0, 160])
cube([(274), 10, 9]);
}
}
}
module VT100_Chin()
{
translate([0, 5, 0]) cube([274, 13, 5.1], false);
difference()
{
translate([0, CaseRounding, CaseRounding])
rotate([0, 90, 0])
cylinder(h=274, r=CaseRounding);
translate([0, 0, 5.1])
cube([274, 18, 10], false);
}
}
module VT100_FrontCutOut()
{
hull()
{
translate([24 - CutOutInset, 0, 27.6 - CutOutInset + CutOutRadius])
sphere(r = InsetRounding);
translate([24 - CutOutInset, 0, 169 + 5.1 - CaseRounding])
sphere(r = InsetRounding);
}
hull()
{
translate([24 + 161 + CutOutInset, 0, 27.6 - CutOutInset + CutOutRadius])
sphere(r = InsetRounding);
translate([24 + 161 + CutOutInset, 0, 169 + 5.1 - 6])
sphere(r = InsetRounding);
}
hull()
{
translate([24 - CutOutInset + CutOutRadius, 0, 27.6 - CutOutInset])
sphere(r = InsetRounding);
translate([24 + 161 + CutOutInset - CutOutRadius, 0, 27.6 - CutOutInset])
sphere(r = InsetRounding);
}
minkowski()
{
translate([24 - CutOutInset + CutOutRadius, 0, 27.6 - CutOutInset + CutOutRadius])
rotate([90, 0, 0])
arc(0.01, 0.01, CutOutRadius, 90);
sphere(r=InsetRounding);
}
minkowski()
{
translate([24 +161 - CutOutInset + CutOutRadius, 0, 27.6 - CutOutInset + CutOutRadius])
rotate([90, 270, 0])
arc(0.01, 0.01, CutOutRadius, 90);
sphere(r=InsetRounding);
}
}
module VT100_TopCutOut()
{
hull()
{
translate([24 - CutOutInset, 6, 169 + 5.1]) sphere(r = InsetRounding);
translate([24 - CutOutInset, 18, 169 + 5.1]) sphere(r = InsetRounding);
}
hull()
{
translate([24 + 161 + CutOutInset, 6, 169 + 5.1]) sphere(r = InsetRounding);
translate([24 + 161 + CutOutInset, 18, 169 + 5.1]) sphere(r = InsetRounding);
}
minkowski()
{
translate([24 - CutOutInset, 6, 169 + 5.1 - CaseRounding])
rotate([0, 90, 0])
arc(0.01, 0.01, CaseRounding, 90);
sphere(r=InsetRounding);
}
minkowski()
{
translate([24 + 161 + CutOutInset, 6, 169 + 5.1 - CaseRounding])
rotate([0, 90, 0])
arc(0.01, 0.01, CaseRounding, 90);
sphere(r=InsetRounding);
}
}
module VT100_LcdFront()
{
translate([24, 0, 27.6])
roundedcube([161, 18, 122], radius = LCDpanelRounding, apply_to = "y");
}
module VT100_LcdPanelCutOut()
{
translate([24 - ((174 - 161) / 2), 2, 27.6 - ((136 - 122) / 2)])
roundedcube([174, 18, 136], radius = LCDpanelRounding, apply_to = "y");
}
module VT100_ChinFaceDivider()
{
translate([0, 0, 5.1])
cube([274, 1, 1]);
}
// Helper functions
module roundedcube(size = [1, 1, 1], center = false, radius = 0.5, apply_to = "all") {
// <https://danielupshaw.com/openscad-rounded-corners/>
// If single value, convert to [x, y, z] vector
size = (size[0] == undef) ? [size, size, size] : size;
translate_min = radius;
translate_xmax = size[0] - radius;
translate_ymax = size[1] - radius;
translate_zmax = size[2] - radius;
diameter = radius * 2;
obj_translate = (center == false) ?
[0, 0, 0] : [
-(size[0] / 2),
-(size[1] / 2),
-(size[2] / 2)
];
translate(v = obj_translate) {
hull() {
for (translate_x = [translate_min, translate_xmax]) {
x_at = (translate_x == translate_min) ? "min" : "max";
for (translate_y = [translate_min, translate_ymax]) {
y_at = (translate_y == translate_min) ? "min" : "max";
for (translate_z = [translate_min, translate_zmax]) {
z_at = (translate_z == translate_min) ? "min" : "max";
translate(v = [translate_x, translate_y, translate_z])
if (
(apply_to == "all") ||
(apply_to == "xmin" && x_at == "min") || (apply_to == "xmax" && x_at == "max") ||
(apply_to == "ymin" && y_at == "min") || (apply_to == "ymax" && y_at == "max") ||
(apply_to == "zmin" && z_at == "min") || (apply_to == "zmax" && z_at == "max")
) {
sphere(r = radius);
} else {
rotate =
(apply_to == "xmin" || apply_to == "xmax" || apply_to == "x") ? [0, 90, 0] : (
(apply_to == "ymin" || apply_to == "ymax" || apply_to == "y") ? [90, 90, 0] :
[0, 0, 0]
);
rotate(a = rotate)
cylinder(h = diameter, r = radius, center = true);
}
}
}
}
}
}
}
/*
* Excerpt from...
*
* Parametric Encoder Wheel
*
* by Alex Franke (codecreations), March 2012
* http://www.theFrankes.com
*
* Licenced under Creative Commons Attribution - Non-Commercial - Share Alike 3.0
*/
module arc( height, depth, radius, degrees )
{
// This dies a horible death if it's not rendered here
// -- sucks up all memory and spins out of control
render() {
difference()
{
// Outer ring
rotate_extrude($fn = 100)
translate([radius - height, 0, 0])
square([height,depth]);
// Cut half off
translate([0,-(radius+1),-.5])
cube ([radius+1,(radius+1)*2,depth+1]);
// Cover the other half as necessary
rotate([0,0,180-degrees])
translate([0,-(radius+1),-.5])
cube ([radius+1,(radius+1)*2,depth+1]);
}
}
}
2D view
$fs=0.3;
$fn=60;
LCDBottom = 27.6;
LCDpanelRoundingRadius = 1.5;
tolerance = 0.05;
cutoutRadius = 10;
cutoutDiameter = 2 + tolerance;
centerLeftCutout = 4.5 + 9.5;
centerRightCutout = 4.5 + 190.5;
cutoutWidth = (centerRightCutout - centerLeftCutout) - (2 * cutoutRadius);
faceWidth = 274;
faceHeight = 169 + 5.1;
VT100FacePoints = [ [ 0, 0],
[ faceWidth, 0],
[(faceWidth - 4.5), faceHeight],
[ 4.5, faceHeight] ];
VT100_Outline();
module VT100_Outline()
{
difference()
{
VT100_Face();
VT100_LcdFront();
VT100_FrontCutOut();
VT100_TopCutOut();
// VT100_ChinFaceDivider();
}
} /* end VT100_Outline */
module VT100_Face()
{
polygon(VT100FacePoints);
} /* end VT100_Face */
module VT100_LcdFront()
{
translate([24, LCDBottom])
rounded_square([161, 122], [LCDpanelRoundingRadius, LCDpanelRoundingRadius, LCDpanelRoundingRadius, LCDpanelRoundingRadius]);
} /* end VT100_LcdFront */
module VT100_FrontCutOut()
{
translate([centerLeftCutout - (cutoutDiameter / 2),
LCDBottom + LCDpanelRoundingRadius])
square([cutoutDiameter, faceHeight - (LCDBottom + LCDpanelRoundingRadius) - cutoutDiameter]);
translate([centerRightCutout - (cutoutDiameter / 2),
LCDBottom + LCDpanelRoundingRadius])
square([cutoutDiameter, faceHeight - (LCDBottom + LCDpanelRoundingRadius) - cutoutDiameter]);
translate([centerLeftCutout + cutoutRadius,
LCDBottom - cutoutRadius - 0.5])
square([161, cutoutDiameter]);
translate([centerLeftCutout - (cutoutDiameter / 2) + cutoutRadius + cutoutDiameter,
LCDBottom + cutoutDiameter - 0.5])
rotate([0, 0, 225])
arc_2D(cutoutRadius, cutoutDiameter, 90);
translate([centerRightCutout - (cutoutDiameter / 2) - cutoutRadius,
LCDBottom + cutoutDiameter - 0.5])
rotate([0, 0, 315])
arc_2D(cutoutRadius, cutoutDiameter, 90);
} /* end VT100_FrontCutOut */
module VT100_TopCutOut()
{
translate([centerLeftCutout - (cutoutDiameter / 2),
faceHeight - cutoutDiameter])
square([cutoutDiameter, cutoutDiameter]);
translate([centerRightCutout - (cutoutDiameter / 2),
faceHeight - cutoutDiameter])
square([cutoutDiameter, cutoutDiameter]);
} /* end VT100_TopCutOut */
module VT100_ChinFaceDivider()
{
translate([0, 5.1])
square([274, cutoutDiameter]);
} /* end VT100_ChinFaceDivider */
// Helper functions
module rounded_square(dim, corners=[10,10,10,10], center=false){
w=dim[0];
h=dim[1];
if (center){
translate([-w/2, -h/2])
rounded_square_(dim, corners=corners);
}else{
rounded_square_(dim, corners=corners);
}
} /* end rounded_square */
module rounded_square_(dim, corners, center=false){
w=dim[0];
h=dim[1];
render()
{
difference(){
square([w,h]);
if (corners[0])
square([corners[0], corners[0]]);
if (corners[1])
translate([w-corners[1],0])
square([corners[1], corners[1]]);
if (corners[2])
translate([0,h-corners[2]])
square([corners[2], corners[2]]);
if (corners[3])
translate([w-corners[3], h-corners[3]])
square([corners[3], corners[3]]);
}
if (corners[0])
translate([corners[0], corners[0]])
intersection(){
circle(r=corners[0]);
translate([-corners[0], -corners[0]])
square([corners[0], corners[0]]);
}
if (corners[1])
translate([w-corners[1], corners[1]])
intersection(){
circle(r=corners[1]);
translate([0, -corners[1]])
square([corners[1], corners[1]]);
}
if (corners[2])
translate([corners[2], h-corners[2]])
intersection(){
circle(r=corners[2]);
translate([-corners[2], 0])
square([corners[2], corners[2]]);
}
if (corners[3])
translate([w-corners[3], h-corners[3]])
intersection(){
circle(r=corners[3]);
square([corners[3], corners[3]]);
}
}
} /* end rounded_square_ */
// https://www.thingiverse.com/thing:1092611
module arc_2D(radius, thick, angle)
{
intersection()
{
union()
{
rights = floor(angle/90);
remain = angle-rights*90;
if(angle > 90)
{
for(i = [0:rights-1])
{
rotate(i*90-(rights-1)*90/2)
{
polygon([[0, 0], [radius+thick, (radius+thick)*tan(90/2)], [radius+thick, -(radius+thick)*tan(90/2)]]);
}
}
rotate(-(rights)*90/2)
polygon([[0, 0], [radius+thick, 0], [radius+thick, -(radius+thick)*tan(remain/2)]]);
rotate((rights)*90/2)
polygon([[0, 0], [radius+thick, (radius+thick)*tan(remain/2)], [radius+thick, 0]]);
}
else
{
polygon([[0, 0], [radius+thick, (radius+thick)*tan(angle/2)], [radius+thick, -(radius+thick)*tan(angle/2)]]);
}
}
difference()
{
circle(radius+thick);
circle(radius);
}
}
} /* end arc_2D */
Top panel
This openSCAD code can generate both 3D and 2D outputs by setting the is3D
variable to
0
or 1
.
$fs=0.3;
$fn=60;
is3D = 1;
topWidth = 265;
topDepth = 182;
topHeight = 12;
topCaseRounding = 6;
cutoutRadius = 10;
cutoutDiameter = 2.05;
centerLeftCutout = 9.5;
centerRightCutout = 190.5;
cutoutLength = (topDepth * 0.60);
cutoutWidth = (centerRightCutout - centerLeftCutout) - (2 * cutoutRadius);
ventilationLeft = centerRightCutout + (cutoutDiameter / 2) + 10;
ventilationRight = topWidth - 10;
ventilationWidth = ventilationRight - ventilationLeft;
if (is3D == 0)
{
difference()
{
VT100_TopPanelWithBackRounding();
VT100_TopCutout();
VT100_ventilation();
}
}
else
{
VT100_TopPanelWithBackRounding();
}
module VT100_ventilation()
{
if (is3D == 1)
{
translate([ventilationLeft-0, 2, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 7, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 12, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 17, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 22, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 27, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 32, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 37, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 42, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 47, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 52, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 57, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 62, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 67, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 72, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 77, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 82, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 87, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 92, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 97, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 102, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 107, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 112, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 117, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 122, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 127, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 132, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 137, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 142, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 147, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 152, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 157, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 162, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
translate([ventilationLeft-0, 167, 0])
cube([ventilationWidth, cutoutDiameter, 12]);
}
else
{
translate([ventilationLeft-0, 2])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 7])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 12])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 17])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 22])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 27])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 32])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 37])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 42])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 47])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 52])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 57])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 62])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 67])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 72])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 77])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 82])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 87])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 92])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 97])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 102])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 107])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 112])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 117])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 122])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 127])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 132])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 137])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 142])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 147])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 152])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 157])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 162])
square([ventilationWidth, cutoutDiameter]);
translate([ventilationLeft-0, 167])
square([ventilationWidth, cutoutDiameter]);
} /* end if */
} /* end VT100_ventilation */
module VT100_TopCutout()
{
if (is3D == 1)
{
translate([centerLeftCutout - (cutoutDiameter / 2),
0,
topHeight - cutoutDiameter])
cube([cutoutDiameter, cutoutLength, cutoutDiameter]);
translate([centerRightCutout - (cutoutDiameter / 2),
0,
topHeight - cutoutDiameter])
cube([cutoutDiameter, cutoutLength, cutoutDiameter]);
translate([centerLeftCutout - (cutoutDiameter / 2) + cutoutRadius,
cutoutLength + cutoutRadius,
topHeight - cutoutDiameter])
cube([cutoutWidth, cutoutDiameter, cutoutDiameter]);
minkowski()
{
translate([centerLeftCutout - (cutoutDiameter / 2) + cutoutRadius,
cutoutLength,
topHeight - cutoutDiameter])
rotate([0, 0, 270])
arc_3D(0.01, 0.01, cutoutRadius, 90);
cube(cutoutDiameter);
}
minkowski()
{
translate([centerRightCutout - (cutoutDiameter / 2) - cutoutRadius,
cutoutLength,
topHeight - cutoutDiameter])
rotate([0, 0, 180])
arc_3D(0.01, 0.01, cutoutRadius, 90);
cube(cutoutDiameter);
}
}
else
{
translate([centerLeftCutout - (cutoutDiameter / 2),
0])
square([cutoutDiameter, cutoutLength]);
translate([centerRightCutout - (cutoutDiameter / 2),
0])
square([cutoutDiameter, cutoutLength]);
translate([centerLeftCutout - (cutoutDiameter / 2) + cutoutRadius,
cutoutLength + cutoutRadius])
square([cutoutWidth, cutoutDiameter]);
translate([centerLeftCutout + (cutoutDiameter / 2) + cutoutRadius,
cutoutLength])
rotate([0, 0, 135])
arc_2D(cutoutRadius, cutoutDiameter, 90);
translate([centerRightCutout - (cutoutDiameter / 2) - cutoutRadius,
cutoutLength])
rotate([0, 0, 45])
arc_2D(cutoutRadius, cutoutDiameter, 90);
} /* end if */
} /* end VT100_TopCutout */
module VT100_TopPanelWithBackRounding()
{
if (is3D == 1)
{
hull()
{
cube([topWidth, topDepth, topCaseRounding]);
translate([0, 0, topCaseRounding])
cube([topWidth, topDepth - topCaseRounding, topCaseRounding]);
VT100_endRounding(topDepth);
}
}
else
{
square([topWidth, topDepth]);
} /* end if */
} /* end VT100_TopPanelWithBackRounding */
module VT100_endRounding(x)
{
if (is3D == 1)
{
translate([0, x - (topCaseRounding * 2), 0])
difference()
{
difference()
{
translate([0, topCaseRounding, topCaseRounding])
rotate([0, 90, 0])
cylinder(topWidth, r=topCaseRounding);
cube([topWidth, topCaseRounding * 2, topCaseRounding]);
}
cube([topWidth, topCaseRounding, topCaseRounding * 2]);
}
}
else
{
// 3D only operation
} /* end if */
} /* end VT100_endRounding */
// Helper functions
/*
* Excerpt from...
*
* Parametric Encoder Wheel
*
* by Alex Franke (codecreations), March 2012
* http://www.theFrankes.com
*
* Licenced under Creative Commons Attribution - Non-Commercial - Share Alike 3.0
*/
module arc_3D( height, depth, radius, degrees )
{
// This dies a horible death if it's not rendered here
// -- sucks up all memory and spins out of control
render() {
difference()
{
// Outer ring
rotate_extrude($fn = 100)
translate([radius - height, 0, 0])
square([height,depth]);
// Cut half off
translate([0,-(radius+1),-.5])
cube ([radius+1,(radius+1)*2,depth+1]);
// Cover the other half as necessary
rotate([0,0,180-degrees])
translate([0,-(radius+1),-.5])
cube ([radius+1,(radius+1)*2,depth+1]);
}
}
}
// https://www.thingiverse.com/thing:1092611
module arc_2D(radius, thick, angle)
{
intersection(){
union(){
rights = floor(angle/90);
remain = angle-rights*90;
if(angle > 90){
for(i = [0:rights-1]){
rotate(i*90-(rights-1)*90/2){
polygon([[0, 0], [radius+thick, (radius+thick)*tan(90/2)], [radius+thick, -(radius+thick)*tan(90/2)]]);
}
}
rotate(-(rights)*90/2)
polygon([[0, 0], [radius+thick, 0], [radius+thick, -(radius+thick)*tan(remain/2)]]);
rotate((rights)*90/2)
polygon([[0, 0], [radius+thick, (radius+thick)*tan(remain/2)], [radius+thick, 0]]);
}else{
polygon([[0, 0], [radius+thick, (radius+thick)*tan(angle/2)], [radius+thick, -(radius+thick)*tan(angle/2)]]);
}
}
difference(){
circle(radius+thick);
circle(radius);
}
}
}
Top side panel
sidePanelPoints = [[0, 0],
[31, 173-12],
[211, 148-12],
[211, 0]];
polygon(sidePanelPoints);
Bottom side panel
$fs=0.3;
$fn=60;
radius = 6;
bottomPlateThickness = 12;
sidePanelPoints = [[0, 0],
[183, 0],
[183, 54-bottomPlateThickness],
[0, 54-bottomPlateThickness]];
polygon(sidePanelPoints);
difference()
{
translate([-6, 54 -radius -bottomPlateThickness]) square(size=6);
translate([-6, 54 -radius -bottomPlateThickness]) circle(r=radius);
}
Inlay panel with picture adjustment controls
$fs=0.3;
$fn=60;
panelThickness = 12;
X = 274 - (2 * panelThickness);
Y = 29 + 12;
offsetX = 240;
offsetY = 8;
inlayPanelPoints = [[0, 0],
[X , 0],
[X, Y],
[0, Y]];
difference()
{
polygon(inlayPanelPoints);
translate([offsetX - 0, offsetY]) circle(r=3);
translate([offsetX - 18, offsetY]) circle(r=3);
translate([offsetX - 30.5, offsetY]) circle(r=3);
translate([offsetX - 46.5, offsetY]) circle(r=3);
translate([offsetX - 64.5, offsetY]) circle(r=3);
}
Bottom panel
$fs=0.3;
$fn=60;
CaseRounding = 6;
hull()
{
hull()
{
translate([0, CaseRounding, CaseRounding])
rotate([0, 90, 0])
cylinder(h=262, r=CaseRounding);
cube([262, CaseRounding, CaseRounding]);
}
hull()
{
translate([0, 183-CaseRounding, CaseRounding])
rotate([0, 90, 0])
cylinder(h=262, r=CaseRounding);
translate([0, 183-CaseRounding, 0])
cube([262, CaseRounding, CaseRounding]);
}
}
Lower front panel
$fs=0.3;
$fn=60;
panelThickness = 12;
X1 = 274 - (2 * panelThickness);
X2 = 262 - (2 * panelThickness);
X2offset = (X1 - X2) / 2;
Y = 42;
lowerFrontPanelPoints = [[X2offset, 0],
[X2+X2offset, 0],
[X1, Y],
[0, Y]];
polygon(lowerFrontPanelPoints);