# Introduction to 3D Modeling. Section 4. Advanced Topics

Objectives:

• Learn about the XOR operation with solid objects.
• Learn to measure dimensions of objects.
• Learn to use Boolean operations more efficiently.

#### 4.1 XOR of objects

XOR ("exclusive or") is after the union, intersection, and difference of objects the last important Boolean operation of solid modeling.

The command XOR(obj1, obj2) creates a new solid object by calculating the union of the objects obj1 and obj2, and subtracting their intersection from it. Mathematically, the resulting object is the set of points that lie either in obj1 or in obj2 but not in both.

For illustration let us overlap two differently rotated cubes, show their union and intersection, and calculate their XOR:

# Create a cube of size 2:
c = CUBE(2)

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

# Rotate cube c by 45 degrees about the z-axis:
d = COPY(c)
ROTATE(d, 45, 3)

# Assign colors:
union = UNION(c, d)
COLOR(union, GOLD)
intersection = INTERSECTION(c, d)
COLOR(intersection, RED)

# Display the result:
SHOW(union, intersection)

# Calculate XOR of c and d, and assign gold color to it:
e = XOR(c, d)
COLOR(e, GOLD)

# Display the result:
SHOW(e)

The two outputs are shown in the left and right parts of Fig. 84.  Fig. 84: Left: cubes c and d with their intersection in red. Right: the XOR of c and d.

#### 4.2 More on scaling

When applying the command SCALE(obj, sx, sy, sz), or its abbreviation S(obj, sx, sy, sz), the x-coordinates of all points in the object obj are multiplied with sx, all y-coordinates with sy, and all z-coordinates with sz. Hence, if the object obj is not centered at the origin, it moves in addition to being scaled. This is best illustrated using a simple script where a cube is moved away from the origin and then scaled down in size several times:

# Create a cube of size 8 and
# move it away from the origin (0, 0, 0):
c = CUBE(8)
MOVE(c, 8, 8, 8)

# Then scale it down to 50% of size several times:
d = COPY(c)
SCALE(d, 0.5, 0.5, 0.5)
e = COPY(d)
SCALE(e, 0.5, 0.5, 0.5)
f = COPY(e)
SCALE(f, 0.5, 0.5, 0.5)
g = COPY(f)
SCALE(g, 0.5, 0.5, 0.5)
h = COPY(g)
SCALE(h, 0.5, 0.5, 0.5)
# Create compound object:
s = [c, d, e, f, g, h]
# Assign gold color to it and display:
COLOR(s, GOLD)
SHOW(s)

The output is shown in Fig. 85. Fig. 85: This experiment illustrates that scaling objects also moves them in space if they are not centered at the origin (0, 0, 0).

#### 4.3 Commands TOP and BOTTOM

The command TOP(obj1, obj2) moves the object obj2 so that it is positioned right above obj1. For illustration, let us create a cube and a sphere, and move the sphere on top of the cube:

c = CUBE(2.0)
s = SPHERE(1.0)
TOP(c, s)

The output is shown in Fig. 86. Fig. 86: Moving a sphere on top of a cube with the TOP command.

Analogously, the command BOTTOM(obj1, obj2) moves the object obj2 under the object obj1. Fig. 87 shows the output of the script

c = CUBE(2.0)
s = SPHERE(1.0)
BOTTOM(c, s) Fig. 87: Moving a sphere under a cube with the BOTTOM command.

In both cases, the object obj2 is aligned in such a way that its center is right above / below the center of obj1.

#### 4.4 Measuring dimensions and printing out information

Sometimes we need to measure the dimensions of an object. The command SIZE( obj, 1) returns the size of the object obj in the first spatial direction (x-axis). Similarly, commands SIZE(obj, 2) and SIZE(obj, 3) return the size of the object obj in the direction of the y-axis and in the direction of the z-axis, respectively. The command print can be used to print out the results. For example, the output of the script

a = BOX(3, 2, 1)
print ~Object dimension in x-direction:~, SIZE(a, 1)

will have the following output:

Object dimension in x-direction: 3.0

The values returned by the SIZE command can be stored in variables and more of them can be printed at the same time. For illustration, the script

a = CYL(1.0, 2.0)
b = COPY(a)
SCALE(b, 2.0, 1.0, 0.5)
dim1 = SIZE(b, 1)
dim2 = SIZE(b, 2)
dim3 = SIZE(b, 3)
print ~Object dimensions:~, dim1, dim2, dim3

will print:

Object dimensions: 4.0 2.0 1.0

#### 4.5 Boolean operations – doing it the wrong way, doing it the right way

Boolean operations can lead to long computations if not done properly. To make them efficient, they should be as much local as possible, meaning that they should occur between as geometrically simple objects as possible.

We will demonstrate this on an example where we first create a vault and then play a gangster and drill a hole into it. Do not worry about the lenght of the script below because the vault has many small parts. But the fact that there are many parts is important here. We will show that while performing a Boolean operation between the drill and the entire vault is extremely time consuming, drilling into just the one relevant part of the geometry is done quickly. First, let us create the vault:

# Define main vault body:
body = BOX(1, 1, 1.2)
interior = BOX(0.86, 0.95, 1.06)
MOVE(interior, 0.07, 0, 0.07)
body = DIFF(body, interior)

# Top part:
top = CHULL([0, 0, 1.2], [1, 0, 1.2], [1, 1, 1.2], \
[0, 1, 1.2], [0.01, 0.01, 1.21], [0.99, 0.01, 1.21], \
[0.99, 0.99, 1.21], [0.01, 0.99, 1.12])

shelf = BOX(1, 0.85, 0.02)
MOVE(shelf, 0, 0.1, 0.4)
shelf2 = COPY(shelf1)
MOVE(shelf2, 0, 0, 0.4)

# Front door:
door = BOX(0.84, 0.05, 1.04)
MOVE(door, 0.08, 0, 0.08)
door_frame = BOX(0.86, 0.03, 1.06)
MOVE(door_frame, 0.07, 0.02, 0.07)

# Truncated cone under the handles:
tcone = TCONE(0.14, 0.13, 0.02)
ROTATE(tcone, 90, 1)
MOVE(tcone, 0.5, 0, 0.6)

# Cylinder that holds the handles:
cyl = CYL(0.07, 0.1)
ROTATE(cyl, 90, 1)
MOVE(cyl, 0.5, 0, 0.6)

# Small truncated cone at the handles:
stcone = TCONE(0.07, 0.06, 0.01)
ROTATE(stcone, 90, 1)
MOVE(stcone, 0.5, -0.1, 0.6)

# Handles:
h1 = CYL(0.022, 0.3)
ts = TCONE(0.022, 0.017, 0.01)
MOVE(ts, 0, 0, 0.3)
h1 = U(h1, ts)
ROTATE(h1, 180./24, 1)
ROTATE(h1, -7*180./24, 2)
h2 = COPY(h1)
ROTATE(h2, -2*180./3, 2)
h3 = COPY(h2)
ROTATE(h3, -2*180./3, 2)
MOVE(h1, 0.5, -0.06, 0.6)
MOVE(h2, 0.5, -0.06, 0.6)
MOVE(h3, 0.5, -0.06, 0.6)

# Bolts:
b1 = CHULL([0.81, 0, 0.19], [0.83, 0, 0.17], [0.97, 0, 0.17], \
[0.97, 0, 0.26], [0.83, 0, 0.26], [0.81, 0, 0.24], [0.815, -0.01, 0.195], \
[0.835, -0.01, 0.175], [0.965, -0.01, 0.175], [0.965, -0.01, 0.255], \
[0.835, -0.01, 0.255], [0.815, -0.01, 0.235])
b2 = COPY(b1)
MOVE(b2, 0, 0, 0.77)

# Bolt cylinder:
bc = CYL(0.015, 0.1, 16)
bc1 = COPY(bc)
MOVE(bc1, 0.925, -0.009, 0.165)
bc2 = COPY(bc1)
MOVE(bc2, 0, 0, 0.77)

# Small bolt sphere:
sbc = SPHERE(0.01, [8, 8])
ROTATE(sbc, 90, 1)
bsc1 = COPY(sbc)
MOVE(sbc1, 0.845, -0.01, 0.195)
sbc2 = COPY(sbc1)
MOVE(sbc2, 0, 0, 0.035)
sbc3 = COPY(sbc1)
MOVE(sbc3, 0, 0, 0.77)
sbc4 = COPY(sbc3)
MOVE(sbc4, 0, 0, 0.035)

# Shelves:
# Vertical handle:
vh = CYL(0.02, 0.5, 16)
MOVE(vh, 0.15, -0.04, 0.35)

# Vertical handle supports:
vh0 = CYL(0.015, 0.06, 16)
ROTATE(vh0, 90, 1)
MOVE(vh0, 0.15, 0.02, 0.4)
vh1 = COPY(vh0)
MOVE(vh1, 0, 0, 0.4)

# Put everything together:
rest = [top, shelf1, shelf2, door, door_frame, tcone, cyl, stcone,
h1, h2, h3, b1, b2, bc1, bc2, sbc1, sbc2, sbc3, sbc4, vh, vh0, vh1]
vault = [body, rest]
SHOW(vault)

The output is shown in Fig. 88. Fig. 88: Vault model.

Now let’s define the drill:

drill = CYL(0.1, 0.5)
ROTATE(drill, 90, 2)
MOVE(drill, 0.1, 0.5, 0.55)

Next let’s drill into the vault. First we will do it the wrong way – drilling into the vault object that consists of many parts.

drilled_vault = DIFF(vault, drill)
SHOW(drilled_vault)

You can run this script but it will take a very long time.

The correct way to do this is to perform the Boolean operation between the drill and the body because the body object is much simpler than the complete vault:

drilled_body = DIFF(body, drill)
SHOW(drilled_body, rest)

Now the computation takes just a few milliseconds! The output is shown in Fig.89. Fig. 89: Vault after subtracting the drill from it.