OpenSCAD and the Tesseract

I’ve been fooling around today with OpenSCAD, an open source program for creating 3D solid CAD objects that you can export as STL files for 3D printing. Unlike SketchUp Make or Tinkercad, where you create three dimensional models interactively by dragging primitives around the design surface, OpenSCAD renders your model from a script you create.

For example, this script.

width = 20;
edge = 5;</p>

<p>difference() {
cube(size = width, center = true);
cube(size = [width - edge, width - edge, width], center = true);
cube(size = [width, width - edge, width - edge], center = true);
cube(size = [width - edge, width, width - edge], center = true);
}

Creates this 3D model.

Snap1

Which can be exported and printed.

IMG_0477

The script is parametric, which mean the model is constructed using parameters. Different size cube frames can be printed by modifying the “width” and “edge” parameters in the script above.

IMG_0478

The cube on the left has a width of 10 and an edge of 3. The cube on the right has a width of 20 and an edge of 5.

So now I thought – what about putting the smaller cube frame inside the larger cube frame, creating a tesseract or hypercube.

600px-Schlegel_wireframe_8-cell

After working on it for a couple of hours I’ve got a partial script that creates the two cubes, one inside the other.

Snap2

But the script is a bit inelegant, subtracting rectangular cubes from the larger cube by “brute force.” I want to work on it a bit more, clean it up so it uses the parameters to derive the coordinates for the subtraction cubes (I also think I can reduce the number of subtraction cubes I currently use). After that I’ll have to figure out how to add the struts to connect the two cubes.

Here’s the script so far.

largeWidth = 20;
largeEdge = 5;</p>

<p>smallWidth = 10;
smallEdge = 3;</p>

<p>difference() {
cube(size = largeWidth, center = true);
cube(size = [smallWidth - smallEdge, smallWidth - smallEdge, largeWidth], center = true);
cube(size = [largeWidth, smallWidth - smallEdge, smallWidth - smallEdge], center = true);
cube(size = [smallWidth - smallEdge, largeWidth, smallWidth - smallEdge], center = true);</p>

<p>// Top
translate([4.5, -8.5, -10])
cube(size = [4.5, 17, largeWidth]);</p>

<p>translate([-largeWidth / 2 + 1, -8.5, -10])
cube(size = [4.5, 17, largeWidth]);</p>

<p>translate([-largeWidth / 2 + 1, -8.5, -10])
cube(size = [17, 4.5, largeWidth]);</p>

<p>translate([-largeWidth / 2 + 1, 4.5, -10])
cube(size = [18, 4.5, largeWidth]);</p>

<p>// Front
translate([4.5, -10, -8.5])
cube(size = [4.5, largeWidth, 17]);</p>

<p>translate([-largeWidth / 2 + 1, -10, -8.5]) // ; at end screws up
cube(size = [4.5, largeWidth, 17]);</p>

<p>translate([-largeWidth / 2 + 1, -10, -8.5])
cube(size = [18, largeWidth, 4]);</p>

<p>translate([-largeWidth / 2 + 1, -10, 5])
cube(size = [18, largeWidth, 4]);</p>

<p>// Side
translate([-largeWidth / 2, 4.5, -8.5])
cube(size = [largeWidth, 4.5, 17]);</p>

<p>translate([-largeWidth / 2, -9, -8.5])
cube(size = [largeWidth, 4.5, 17]);</p>

<p>translate([-largeWidth / 2, -9, 4.5])
cube(size = [largeWidth, 18, 4.5]);</p>

<p>translate([-largeWidth / 2, -9, -largeWidth / 2 + 1])
cube(size = [largeWidth, 18, 4.5]);</p>

<p>// Remove debris frames
translate([0, 0, 7])
cylinder(h = 3, r = largeWidth / 2 - 2);</p>

<p>translate([0, 0, -11])
cylinder(h = 3, r = largeWidth / 2 - 2);</p>

<p>translate([0, -8, 0])
rotate(a=[90, 0, 0])
cylinder(h = 3, r = largeWidth / 2 - 2);</p>

<p>translate([0, 10.5, 0])
rotate(a=[90, 0, 0])
cylinder(h = 4, r = largeWidth / 2 - 2);</p>

<p>translate([8.5, 0, 0])
rotate(a=[0, 90, 0])
cylinder(h = 3, r = largeWidth / 2 - 2);</p>

<p>translate([-10.5, 0, 0])
rotate(a=[0, 90, 0])
cylinder(h = 3, r = largeWidth / 2 - 2);
}

Here’s an updated script. I reduced the number of subtraction cubes from eighteen to six and the cube frame widths are more consistent but there’s still to many “magic numbers” for my liking (I feel I should be able to derive all numbers I need from the large and small widths and edges but it’s not working out right now).

Snap5

largeWidth = 20;
largeEdge = 5;</p>

<p>smallWidth = 10;
smallEdge = 3;</p>

<p>difference() {
cube(size = largeWidth, center = true);
cube(size = [smallWidth - smallEdge, smallWidth - smallEdge, largeWidth], center = true);
cube(size = [largeWidth, smallWidth - smallEdge, smallWidth - smallEdge], center = true);
cube(size = [smallWidth - smallEdge, largeWidth, smallWidth - smallEdge], center = true);</p>

<p>translate([smallWidth / 2, -11 + largeEdge / 2, -(largeWidth / 2) + 1.75])
cube(size = [largeEdge, largeWidth - 3.5, largeWidth - 3.5]);</p>

<p>translate([-largeWidth / 2, -11 + largeEdge /2, -(largeWidth / 2) + 1.75])
cube(size = [largeEdge, largeWidth - 3.5, largeWidth - 3.5]);</p>

<p>translate([-largeWidth / 2 + 1.75, -(largeWidth / 2) + largeEdge, -(largeWidth / 2) + 1.75])
rotate(a = [0, 0, 270])
cube(size = [largeEdge, largeWidth - 3.5, largeWidth - 3.5]);</p>

<p>translate([-largeWidth / 2 + 1.75, smallWidth + 2.5, -(largeWidth / 2) + 1.75])
rotate(a = [0, 0, 270])
cube(size = [largeEdge + 2.5, largeWidth - 3.5, largeWidth - 3.5]);</p>

<p>translate([-largeWidth / 2 + 1.75, -(largeWidth / 2) + 1.75, largeEdge])
rotate(a = [0, 0, 0])
cube(size = [largeWidth - 3.5, largeWidth - 3.5, largeWidth - 3.5]);</p>

<p>translate([-(largeWidth / 2) + 1.75, -(largeWidth / 2) + 1.75, -(largeWidth / 2) + 5])
rotate(a = [0, 90, 0])
cube(size = [largeWidth - 3.5, largeWidth - 3.5, largeWidth - 3.5]);
}

I’m also not sure how to create the struts that I need to attach the external corners of the smaller cube to the internal corners of the larger cube. At first I thought I’d modify the subtraction cubes into pyramids with their tops lopped off and then use six of these in different rotations to carve chunks out of the big cube. That’s 12 points and 16 triangles per “pyramid” for a total of 72 points and 96 triangles.

Snap3

Then I thought about using the entire pyramid with its tip at 0, 0, 0 and its base points at four of the larger cubes inner vertexes (again, I’d need six of these in various rotations to carve up the big cube. That’s 5 points and 6 triangles per pyramid for a total of 30 points and 36 triangles.

Snap4

Now I’m thinking that maybe I should calculate the sixteen vertexes of both cubes and construct the cubes and their connecting struts using those sixteen points and rectangular cubes.

Snap6

The larger square vertexes are blue; the smaller square vertexes are red. Here’s the script that created both sets of vertexes.

largeWidth = 20;
largeEdge = 3;</p>

<p>smallWidth = 10;
smallEdge = 2;</p>

<p>// Outer cube</p>

<p>frontUpperLeftLarge = [-largeWidth / 2, -largeWidth / 2, largeWidth / 2];
frontUpperRightLarge = [largeWidth / 2, -largeWidth / 2, largeWidth /2];
frontLowerLeftLarge = [-largeWidth / 2, -largeWidth / 2, -largeWidth / 2];
frontLowerRightLarge = [largeWidth / 2, -largeWidth / 2, -largeWidth / 2];</p>

<p>backUpperLeftLarge = [-largeWidth / 2, largeWidth / 2, largeWidth / 2];
backUpperRightLarge = [largeWidth / 2, largeWidth / 2, largeWidth /2];
backLowerLeftLarge = [-largeWidth / 2, largeWidth / 2, -largeWidth / 2];
backLowerRightLarge = [largeWidth / 2, largeWidth / 2, -largeWidth / 2];</p>

<p>translate(frontUpperLeftLarge) color("blue") cube(size = largeEdge, center = true);
translate(frontUpperRightLarge) color("blue") cube(size = largeEdge, center = true);
translate(frontLowerLeftLarge) color("blue") cube(size = largeEdge, center = true);
translate(frontLowerRightLarge) color("blue") cube(size = largeEdge, center = true);</p>

<p>translate(backUpperLeftLarge) color("blue") cube(size = largeEdge, center = true);
translate(backUpperRightLarge) color("blue") cube(size = largeEdge, center = true);
translate(backLowerLeftLarge) color("blue") cube(size = largeEdge, center = true);
translate(backLowerRightLarge) color("blue") cube(size = largeEdge, center = true);</p>

<p>// Inner cube</p>

<p>frontUpperLeftSmall = [-smallWidth / 2, -smallWidth / 2, smallWidth / 2];
frontUpperRightSmall = [smallWidth / 2, -smallWidth / 2, smallWidth /2];
frontLowerLeftSmall = [-smallWidth / 2, -smallWidth / 2, -smallWidth / 2];
frontLowerRightSmall = [smallWidth / 2, -smallWidth / 2, -smallWidth / 2];</p>

<p>backUpperLeftSmall = [-smallWidth / 2, smallWidth / 2, smallWidth / 2];
backUpperRightSmall = [smallWidth / 2, smallWidth / 2, smallWidth /2];
backLowerLeftSmall = [-smallWidth / 2, smallWidth / 2, -smallWidth / 2];
backLowerRightSmall = [smallWidth / 2, smallWidth / 2, -smallWidth / 2];</p>

<p>translate(frontUpperLeftSmall) color("red") cube(size = smallEdge, center = true);
translate(frontUpperRightSmall) color("red") cube(size = smallEdge, center = true);
translate(frontLowerLeftSmall) color("red") cube(size = smallEdge, center = true);
translate(frontLowerRightSmall) color("red") cube(size = smallEdge, center = true);</p>

<p>translate(backUpperLeftSmall) color("red") cube(size = smallEdge, center = true);
translate(backUpperRightSmall) color("red") cube(size = smallEdge, center = true);
translate(backLowerLeftSmall) color("red") cube(size = smallEdge, center = true);
translate(backLowerRightSmall) color("red") cube(size = smallEdge, center = true);

This entry was posted in Other and tagged . Bookmark the permalink.