# Introduction to 3D Modeling. Section 3. First Projects

### 3 First Projects

#### 3.1 Aquarium stand

Objectives:

• Move objects using 3D vectors.
• Display differently colored objects in one scene.
• Merge multiple objects into a new solid object.

You just bought a new aquarium and need to build a stand for it. The stand that you have in mind is shown in Fig. 47. Fig. 47: Aquarium stand.

The dimensions of the aquarium are 70 cm, 40 cm, and 50 cm. Therefore, the outer horizontal dimensions of the stand will be 70 cm and 40 cm. The stand will be made of 1 × 1 inch bars (1 inch = 2.54 cm), and including a half-inch thick wooden plate on top its height should be 60 cm. For stability reasons, the stand should be reinforced with horizontal bars located 10 cm above ground. Ready?

##### Design:

To begin with, create variables for all measures and dimensions. Doing this at the beginning of every new project is a good habit – it allows you to easily tweak the design later.

e = 2.54          # Edge of the cross-section of the bar.
height = 60       # Height of stands including wood.
height_r = 10     # Height of reinforcements.
xdim = 70         # Width of the aquarium.
ydim = 40         # Depth of the aquarium.
zdim = 50         # Height of the aquarium.

Notice that the hash symbol ’#’ introduces a comment. This is another Python thing – all text after this symbol till the end of line is ignored by the interpreter.

The first leg of the stand is defined using the BOX command:

l1 = BOX(e, e, height - 0.5 * e)

Next we need to create the three other legs. For this we need to introduce the MOVE command:

The command MOVE(obj, tx, ty, tz) moves the object obj by tx, ty, tz in the x, y and z axial directions, respectively. In other words, the object obj is moved by the 3D vector (tx, ty, tz).

Minding the thickness of the bars, the remaining three legs of the satnd are created via

l2 = COPY(l1)
MOVE(l2, xdim - e, 0, 0)
l3 = COPY(l1)
MOVE(l3, 0, ydim - e, 0)
l4 = COPY(l1)
MOVE(l4, xdim - e, ydim - e, 0, 0)

The partial design is displayed in steel color as follows:

SHOW(l1, l2, l3, l4)

Fig. 48 shows how our design looks at the moment. Fig. 48: Four legs of the stand.

Often there are multiple ways that lead to the same design. Here, the four legs together form a Cartesian product geometry: Two intervals in the x-direction times two intervals in the y-direction times one interval in the z-direction. So, the same could be done using the GRID and PRODUCT commands that were introduced in Subsection 2.25:

g1 = GRID(e, -width - 2*e, e)
g2 = GRID(e, -depth - 2*e, e)
g12 = PRODUCT(g1, g2)
g3 = GRID(height - 0.5 * e)
legs = PRODUCT(g12, g3)

Next let’s take care of the horizontal bars. First the top ring:

# Create top bars:
t1 = BOX(xdim, e, e)
MOVE(t1, 0, 0, height - 0.5*e - e)
t2 = COPY(t1)
MOVE(t2, 0, ydim - e, 0)
t3 = BOX(e, ydim, e)
MOVE(t3, 0, 0, height - 0.5*e - e)
t4 = COPY(t3)
MOVE(t4, xdim - e, 0, 0)

# Display the frame:
SHOW(l1, l2, l3, l4, t1, t2, t3, t4)

The design after this step is shown in Fig. 49. Fig. 49: Four legs and the top ring.

The reinforcement ring is obtained by lowering the top ring by height - height_r:

# Create bottom reinforcement bars:
b1 = COPY(t3)
MOVE(b1, 0, 0, -(height - height_r))
b2 = COPY(t4)
MOVE(b2, 0, 0, -(height - height_r))
b3 = COPY(t1)
MOVE(b3, 0, 0.5*(ydim - e), -(height - height_r))

Finally, we display the frame:

# Display the frame:
SHOW(l1, l2, l3, l4, t1, t2, t3, t4, b1, b2, b3)

The design after this step is shown in Fig. 50. Fig. 50: Complete frame.

After checking visually that all parts of the frame are correct, let us create a new solid object for the frame by merging all 12 bars together. For this, we use the command UNION.

The command UNION(obj1, obj2, obj3, ...), that can be abbreviated by U, creates a new solid object by merging the objects obj1, obj2, obj3, ... together. Mathematically, the resulting object is the set of all points that belong to at least one of these objects.

In our case we create the new object for the frame as follows:

# Create new solid object by merging all parts:
frame = U(l1, l2, l3, l4, t1, t2, t3, t4, b1, b2, b3)

As every newly created object, frame has the default steel color. Last, the top plate is a BOX(xdim, ydim, 0.5*e) that is lifted up by height - 0.5*e:

# Create the top plate:
top = BOX(xdim, ydim, 0.5*e)
MOVE(top, 0, 0, height - 0.5*e)

# Display frame and top plate together:
wood = [102, 51, 0]
COLOR(top, wood)
SHOW(frame, top)

The final design is shown in Fig. 51. #### 3.2 Water molecule

Objectives: Rotate 3D objects.

Your task is to create a ball-and-stick model of the molecule of water (H2O) shown in Fig. 52. Fig. 52: Water molecule model: oxygen (red), hydrogens (cyan), and bonds (gray).

The only physical parameter that you have to preserve is the angle between the two hydrogen atoms which is 104.45 degrees. All other dimensions of your model should be variable.

##### Design:

To begin with, define colors for the molecules and the bonds:

Color_O = [200, 0, 0]
Color_H = [0, 200, 200]
Color_bond = [200, 200, 200]

Next create variables for all parameters of the model:

R_O = 1.0         # Radius of the O atom.
R_H = 0.7         # Radius of the H atom.
R_bond = 0.1      # Radius of the sticks.
L_bond = 0.2      # Distance of O and H atoms.
Angle = 104.45    # Angle between H atoms (in degrees).

For practical reasons, let us redefine the length of the bond to span the distance between the centers of the O and H atoms:

L_bond = L_bond + R_O + R_H

Now create the atom of oxygen and one atom of hydrogen:

Sphere_O = SPHERE(R_O)
Sphere_H = SPHERE(R_H)

If we displayed them together right now, then the H atom would not be visible since it would be inside the O atom. So, let us move the H atom by the length of the bond in the direction of the x-axis:

MOVE(Sphere_H, L_bond, 0, 0)

The current state of our model is shown in Fig. 53. Fig. 53: O and H atoms.

Next create a cylinder (stick) representing the bond:

Bond = CYL(R_bond, L_bond)

After this command, the situation is depicted in Fig. 54. Fig. 54: Creating a cylinder to model the bond.

Of course this is not what we want – the bond need to be connecting the O and H atoms. Hence we will need to rotate the cylinder by 90 degrees about the y-axis. This is done with the ROTATE command.

The command ROTATE(obj, angle_in_degrees, axis) that can be abbreviated as R(obj, angle_in_degrees, axis), returns a new object that is obtained by rotating the object obj counter-clockwise (CCW) about the axis axis by angle angle. Here axis = 1 for the x-axis, axis = 2 for the y-axis and axis = 3 for the z-axis. By default, angle is in degrees. Commands ROTATERAD and RRAD can be used with angles in radians.

Hence the following command will rotate the bond to the correct position:

ROTATE(Bond, -90, 2)

The updated geometry is shown in Fig. 55. Fig. 55: Rotating the cylinder by 90 degrees.

Last, rotate both the cylinder and the hydrogen atom, assign colors, and diplay:

Bond_2 = COPY(Bond)
ROTATE(Bond_2, Angle, 3)
Sphere_H_2 = COPY(Sphere_H)
ROTATE(Sphere_H_2, Angle, 3)

COLOR(Sphere_O, Color_O)
COLOR(Sphere_H, Color_H)
COLOR(Sphere_H_2, Color_H)
COLOR(Bond, Color_bond)
COLOR(Bond_2, Color_bond)

SHOW(Sphere_O, Sphere_H, Bond, Sphere_H_2, Bond_2)

The final geometry of the molecule is displayed in Fig. 56. Fig. 56: Final design.

#### 3.3 Coffee table

Objectives:

• Scale objects.
• Subtract objects from each other.

Your third task is to create a model of an oval coffee table that is shown in Fig. 57. Fig. 57: Oval coffee table.

This is a real coffee table that is sold by the Fong Brothers Company in Los Angeles. The width, depth and height of the table are 48, 24 and 18 inches, respectively.

##### Design:

As usual we first introduce variables for all design parameters:

w = 48.0           # Width.
d = 24.0           # Depth.
h = 18.0           # Height.
top_outer = 4.5    # Thickness of top (outer view).
top_inner = 1.0    # Thickness of top (inner view).
leg_width = 7.0    # Width of legs.
leg_depth = 2.0    # Depth of legs.

The departure point for the design will be a cylinder of radius d/2 and height h:

body = CYL(d/2.0, h, 128)

which is shown in Fig. 58. Fig. 58: The design starts with a cylinder.

In the next step, the cylinder will be transformed to an oval cylinder via the SCALE command.

The command SCALE(obj, sx, sy, sz) that can be abbreviated simply as S(obj, sx, sy, sz) stretches or shrinks the object obj by sx, sy, sz in the x, y and z axial directions, respectively.

We will be scaling an object body by w / d in the x-direction:

SCALE(body, w / d, 1.0, 1.0)

The result after scaling is shown in Fig. 59. Fig. 59: Scaling by 2.0 in the x-direction.

Now we need to cut off four corners in order to define the width of the legs. This is done via the command DIFFERENCE.

The command DIFFERENCE(obj, cut1, cut2, ...), possibly abbreviated as DIFF or D, creates a new solid object by subtracting the objects cut1, cut2, ... from the object obj. Mathematically, the resulting object is the set of all points that belong to object obj but do not lie in cut1, cut2, ....

The object to be subtracted from the oval cylinder will be constructed by subtracting two boxes from a larger box:

b = BOX(w, d, h - top_outer)
MOVE(b, -w/2.0, -d/2.0, 0)
b_cut1 = COPY(b)
SCALE(b_cut1, leg_width / w, 1.0, 1.0)
b_cut2 = COPY(b)
SCALE(b_cut2, 1.0, leg_width / d, 1.0)
b = DIFF(b, b_cut1, b_cut2)

The object b is displayed in Fig. 60. Fig. 60: Object to be subtracted from the oval cylinder.

Next we subtract b from body,

table = DIFF(body, b)

and display the result in Fig. 61. Fig. 61: Oval cylinder after subtracting the object b.

Note that we preserved the original oval cylinder in the variable body. Now we will scale it down as needed in order to remove the interior part of the table:

# Scale down the object ~body~:
SCALE(body, (w - 2*leg_depth) / w, \
(d - 2*leg_depth) / d, (h - top_inner) / h)

# Display it along with the object ~table~:
SHOW(table, body)

The situation is depicted in Fig. 62. Fig. 62: Table before removing the inner part.

As the last step, we remove the object body from the object table:

table = DIFF(table, body) Fig. 63: Final design.

#### 3.4 Geometry labs

Objectives:

• Intersect 3D objects with planes represented by thin 3D solids.
• Experiment with conic sections.

PLaSM makes it possible to intersect objects via the INTERSECTION command.

The command INTERSECTION(obj1, obj2, obj3, ...) that can be abbreviated as I(obj1, obj2, obj3, ...) creates a new solid object by intersecting the objects obj1, obj2, obj3, .... Mathematically, the resulting object is the set of all points that belong to all the objects. In other words, if some point does not lie in one of the objects, it does not belong to the intersection.

In this subsection we will be using cones and planes to construct conic sections. With what you learn here, you will be able to cut any other 3D objects.

Let us begin with creating a cone of radius r = 1 and height h = 2:

r = 1.0
h = 2.0
cone = CONE(r, h, 128)
COLOR(cone, GOLD)
SHOW(cone)

The parameters r and h are variables that you can change them easily if needed. The optional third parameter 128 in the cone’s definition is used to make the surface smoother-looking (recall from Subsection 2.18 that the default value is 64). The cone is shown in Fig. 64. Fig. 64: Cone with radius r = 1 and height h = 2.

#### Constructing a circle

A circle is obtained by cutting the cone with a plane that is normal (perpendicular) to its axis. Hence, let’s add a plane, represented by a square of size s = 3. The square will be created using the SQUARE3D command and displayed along with the cone in steel color:

s = 3.0
plane = SQUARE3D(s)
COLOR(cone, GOLD)
SHOW(cone, plane)

The two objects are shown together in Fig. 65. Fig. 65: Square is created at its default position in the first quadrant.

We need to move the square in the xy-plane so that the z-axis passes through its center, and at the same time to lift it by e in the z-direction. Hence the 3D translation vector is (-s/2.0, -s/2.0, e):

e = 1.0
MOVE(plane, -s/2.0, -s/2.0, e)
COLOR(cone, GOLD)
SHOW(cone, plane)

The situation is depicted in Fig. 66. Fig. 66: Square is centered and lifted to elevation e.

Now we can create the conic section:

circle = INTERSECTION(cone, plane)
COLOR(circle, GOLD)
SHOW(circle)

The intersection is shown in Fig. 67. Fig. 67: The circular conic section.

We can also visualize the intersection with the rest of the plane. For this, we subtract the cone from the plane, and view it together with the circle:

pierced_plane = DIFF(plane, cone)
COLOR(circle, GOLD)
SHOW(circle, pierced_plane)

The ensemble is shown in Fig. 68. Fig. 68: The conic section displayed along with the rest of the plane.

Let’s play some more! We can cut off the upper part of the cone, to obtain a truncated cone. This can be done using the same sequence of operations as above, only the plane will be replaced by a half-space, represented by a cube. Let us display the two objects together first:

s = 3.0
cube = CUBE(s)
e = 1.0
MOVE(cube, -s/2.0, -s/2.0, e)
COLOR(cone, GOLD)
SHOW(cone, cube)

The two objects are displayed in Fig. 69. Fig. 69: The cone and the half-space, represented by a large cube.

Next let us remove the half-space from the cone:

tcone = DIFF(cone, cube)
COLOR(tcone, GOLD)
SHOW(tcone)

The result is shown in Fig. 70. Fig. 70: Removing the half-space from the cone yields a truncated cone.

The upper part of the cone is an intersection of the cone with the cube:

tip = INTERSECTION(cone, cube)
COLOR(tcone, GOLD)
SHOW(tcone, tip)

The truncated cone in gold color, along with the upper part in steel color, are shown in Fig. 71. Fig. 71: The two parts of the cone shown in different colors.

#### The math behind the scenes

The equation for the cone of radius r and height h shown in Fig. 64 is In other words, all 3D points that satisfy the above equation belong to the surface of the cone. The plane shown in Fig. 66 is described via the equation The intersection of the plane and the surface of the cone is formed by all points that satisfy the above two equations at the same time. Hence, we obtain After a simple manipulation that involves dividing the equation by h, subtracting 1 from both sides, and multiplying the equation with r, we obtain Here, is the distance of the point (x,y,z) from the z-axis. Hence, the last equation represents a set of all 3D points whose distance from the z-axis is r(1 - e∕h). This is a cylindrical surface. But keeping in mind that we also have the equation z = e, the resulting set of points is a circle whose center lies on the z-axis and whose elevation above the xy-plane is e.

#### Constructing an ellipse

An ellipse is obtained by intersecting the cone with a plane that is not normal to the cone axis, but that is also not steeper that the slope of the cone. For this example we will use the cone from Fig. 64, but we will make it three times bigger (both r and h) and move it by -4 units on the z-axis so that its apex is at z = 2 as before:

r = 3.0
h = 6.0
cone = CONE(r, h, 128)
MOVE(cone, 0, 0, -4)

Next we add a plane represented by a square of size s = 7, move it so that its center lies on the z-axis, and rotate by 45 degrees about the y-axis:

s = 7.0
plane = SQUARE3D(s)
MOVE(plane, -s/2.0, -s/2.0, 0)
ROTATE(plane, 45, 2)
COLOR(cone, GOLD)
SHOW(cone, plane)

The situation is shown in Fig. 72. Fig. 72: The cone and the plane.

With both objects in place, we can create their elliptic intersection. It will be displayed in gold color along with the rest of the plane in steel color:

ellipse = INTERSECTION(cone, plane)
pierced_place = DIFF(plane, cone)
COLOR(ellipse, GOLD)
SHOW(ellipse, pierced_plane)

The result is shown in Fig. 73. Fig. 73: The elliptic intersection.

Finally, if we like to, we can remove the upper part of the cone in the same way we did before – replacing the plane with a cube, translating and rotating the cube in the same way as the plane, and subtracting it from the cone. The result is shown in Fig. 74. Fig. 74: Exposing the elliptic cut.

#### Constructing a parabola

Parabola is obtained when a cone is intersected with a plane that has the same slope as the surface of the cone, and that does not pass through its apex. We will stay with the same cone as before, just the plane will be enlarged:

s = 10.0
plane = SQUARE3D(s)
MOVE(plane, -s/2.0, -s/2.0, 0)

To calculate the slope of the plane, we import the arctan function from Numpy, Python’s numerical computation library:

from numpy import arctan
alpha = arctan(h/r) * 180 / PI

Next we rotate the plane by angle alpha about the y-axis:

ROTATE(plane, alpha, 2)
COLOR(cone, GOLD)
SHOW(cone, plane)

Note that this rotation is in radians, not in degrees – this is because the function arctan returns angles in radians. The two objects are shown in Fig. 75. Fig. 75: The cone and the plane.

Now we can calculate the intersection of the plane with the cone, and display it along with the rest of the plane:

parabola = INTERSECTION(cone, plane)
pierced_plane = DIFF(plane, parabola)
COLOR(parabola, GOLD)
SHOW(parabola, pierced_plane)

The parabola is shown in Fig. 76. Fig. 76: Parabolic intersection (truncated).

Note that the parabola is truncated because both the cone and the plane are represented by objects of finite size. Ideally, if both of them were infinite, also the parabola would extend to infinity.

Last we can replace the plane with a cube, and remove the upper part of the cone:

s = 10.0
cube = CUBE(s)
MOVE(cube, -s/2.0, -s/2.0, 0)
ROTATE(cube, alpha, 2)
tcone = DIFF(cone, cube)
COLOR(tcone, GOLD)
SHOW(tcone)

The result is shown in Fig. 77. Fig. 77: Exposing the parabolic cut.

#### Constructing a hyperbola

Hyperbola is obtained by intersecting the cone with a plane that is either parallel to the axis of the cone, or its slope is steeper than the slope of the surface of the cone.

Hyperbolas have two arms, therefore we will use the full mathematical form of the cone which we did not need until now. It consists of two "usual" cones that share the same axis and touch at the apex. They are constructed as follows:

r = 3.0
h = 6.0
cone1 = CONE(r, h, 128)
MOVE(cone1, 0, 0, -6)
cone2 = COPY(cone1)
ROTATE(cone2, 180, 1)
cone = UNION(cone1, cone2)

The double cone is shown in Fig. 78. Fig. 78: The double cone.

Next let us create the plane. We will create a sufficiently large square using the SQUARE3D command, and move it so that its center lies on the z-axis:

s = 12.0
plane = SQUARE3D(s)
MOVE(plane, -s/2.0, -s/2.0, 0)

The plane is rotated by angle alpha about the y-axis. This angle does not have to be 90 degrees as in our example below. But the slope of the cone must not become less than or equal to the slope of the cone – otherwise we would end up with an ellipse or parabola:

alpha = 90
ROTATE(plane, alpha, 2)

The plane should not pass through the apex:

D = -0.5
MOVE(plane, D, 0, 0)

Let’s display the two objects together:

COLOR(cone, GOLD)
SHOW(cone, plane)

The double cone and the plane are shown in Fig. 79. Fig. 79: The double cone and the plane.

Now we can already create the hyperbolic intersection:

hyperbola = INTERSECTION(cone, plane)
pierced_plane = DIFF(plane, hyperbola)
COLOR(hyperbola, GOLD)
SHOW(hyperbola, pierced_plane)

The output is shown in Fig. 80. Fig. 80: Hyperbolic intersection.

Finally, as we did in the previous examples, let us replace the plane with a cube, and expose the hyperbolic cut by removing part of the double cone:

# Replace the plane with a cube, move
# and rotate it in the same way, and subtract
# from the cone:
s = 12.0
cube = CUBE(s)
MOVE(cube, -s/2.0, -s/2.0, 0)
# Rotate the cube by 90 degrees
alpha = 90
ROTATE(cube, alpha, 2)

# Move the cube a bit from the origin:
D = -0.5
MOVE(cube, D, 0, 0)
# Subtract the cube from the cone:
tcone = DIFF(cone, cube)
COLOR(tcone, GOLD)
SHOW(tcone)

What remains of the double cone is shown in Fig. 81. Fig. 81: Exposing the hyperbolic cut.

#### 3.5 3D puzzle

Objectives: Intersect 3D objects.

Construct a 3D object that can fit exactly into all three holes in the wooden piece shown in Fig. 82! Fig. 82: 3D puzzle.

The three holes have the following parameters:

• 2 × 2 inch square,
• symmetric triangle of base 2 inches and height 2 inches,
• circle of radius 1.0 inches.

Impossible? Turn the page.

#### Solution   Fig. 83: Solution of the 3D puzzle.

Here is the script that creates the object:

# First create a cube of size 2:
c = CUBE(2.0)

# Move the cube so that its center lies at (0, 0, 0):
MOVE(c, -1, -1, -1)

# Next create a cylinder with radius 1 and height 2:
cyl = CYL(1, 2)

# Move also the cylinder so that its center lies at (0, 0, 0):
MOVE(cyl, 0, 0, -1)

# Create a prism via convex hull:
p = CHULL([1, -1, -1], [1, 0, 1], [1, 1, -1], \
[-1, -1, -1], [-1, 0, 1], [-1, 1, -1])

# Calculate the intersection of the three objects:
out = INTERSECTION(c, cyl, p)