A *code-along* is a story about coding in which you are encouraged to “code up” all the examples in the story. In a code-along you should**not** cut-and-paste.

In this code-along we will explore how 2-dimensional LEGO artifacts can be projected onto 3-dimensional artifacts. For example, a chessboard pattern can be projected onto a sphere. One can also project 2-dimensional pixel art onto a sphere. We will explore two ways in which such projection can be accomplished.

## Code-along Program 1

Program 1 uses a traversal to create a picture frame consisting of a black border and red center. Note that the variable *onFrame* holds the result of a Boolean expression that evaluates to *true* when the x and z values of a point have properties that are *necessary* (though not*sufficient*) for points that reside in the frame of the picture; otherwise the point has properties that are necessary for points that reside in the center portion of the picture frame. In order for a point to reside in the picture frame, it must also have a y value equal to 0. A nested conditional expression in the body of the function *buildPictureFrame* assures that points in the picture frame (1) reside in the xz-plane with y = 0, and (2) are black if the xz component of the point places the point on the frame and red otherwise.

Note that in this program the *dimensions* of Bricklayer’s virtual space and the *max* value of the x,y, and z components of a location are declared at the top-level of the program using val-declarations. This permits experimentation with the size of the virtual space, by changing just one number.

```
open Level 5;
val dimensions = 16;
val max = dimensions-1;
fun pictureFrame () =
let
val lower = 4;
val upper = 11;
fun buildPictureFrame(x,y,z) =
let
val onFrame = x < lower orelse z < lower
orelse
x > upper orelse z > upper;
in
if y = 0 then
if onFrame then BLACK else RED
else EMPTY
end;
in
traverseWithin (0,0,0)
(max,max,max)
buildPictureFrame
end;
build(dimensions,dimensions,dimensions);
pictureFrame();
show "picture frame";
```

## Code-along Program 2

In this program we see how, through a slight modification, we can project a pictureFrame onto a slanted plane. The basic approach is as follows: We begin with an artifact (e.g., a pictureFrame) whose construction is governed by a predicate *p* which is parameterized on x and z. Examples of artifacts that can be constructed using such predicates include pictureFrames, chessboards, and targets. Next we define a predicate *q* to construct a slanted plane (e.g., y = z).

Our projection is then created using a nested conditional where the first condition determines whether a point under consideration lies on the slanted plane. This first condition, in effect, acts like a filter – it filters, from the points traversed, those points that lie on the slanted plane. The x and z values of these points lying on the slanted plane are then evaluated with respect to the (secondary) property *p*. The result is a projection of the artifact defined by *p* (e.g., the pictureFrame) onto the slanted planed defined by *q*.

```
open Level 5;
val dimensions = 16;
val max = dimensions-1;
fun pictureFrame () =
let
val lower = 4;
val upper = 11;
fun p(x,z) = x < lower orelse z < lower
orelse
x > upper orelse z > upper;
fun q(y,z) = y = z;
fun buildPictureFrame(x,y,z) =
let
val onSlantedPlane = q(y,z);
val onFrame = p(x,z);
in
if onSlantedPlane then
if onFrame then BLACK else RED
else EMPTY
end;
in
traverseWithin (0,0,0)
(max,max,max)
buildPictureFrame
end;
build(dimensions,dimensions,dimensions);
pictureFrame();
show "picture frame";
```

## Code-along Program 3

In this program we look at a 2D artifact whose construction is not predicate-based. Pixel art images are classic examples of such artifacts. The program below involves the creation of a black number 8 on a white circular surface. The original artifact is two dimensional. However, the code below expands the artifact to three dimensions. The 3D artifact created can be thought of as simply a stack of the original two dimensional artifacts. Note that this stack can be made as tall as desired. However, it should be noted that such solid artifacts contain a large number of bricks. For example, the artifact shown in this example has 7490 bricks. The number of bricks in a 3D object is an important metric to be aware of because in general LEGO Digital Designer has difficulty displaying artifacts containing more than 25K bricks.

```
open Level 5;
val dimensions = 64;
val max = dimensions-1;
fun eight (x,y,z) =
let
val r = 5;
val numTthickness = 3;
val bgThickness = 3*r + 1;
in
ringY (r*3) bgThickness 10 [WHITE] (x,y,z);
ringY r numThickness 10 [BLACK] (x+r,y,z);
ringY r numThickness 10 [BLACK] (x-r,y,z)
end;
build(dimensions,10,dimensions);
eight(30,0,30);
show "Eight";
```

## Code-along Program 4

The artifact created by this program is an eight ball. The artifact is hollow, but nevertheless contains 27748 bricks. The eight ball is created by first creating a stack of eights in the virtual space. This stack contains 47187 bricks. This stack artifact, which we will call the *eight-stack* represents an intermediate stage of the construction of the eight ball and is not displayed. A black sphere is then created in the same space where the *eight-stack* resides. The formula for creating a sphere is simply the extension to three dimensions of the formula used to create a circle. There are several things about how the sphere is constructed that are worth mentioning (1) the sphere is hollow, (2) all points outside of the sphere (e.g., points that may have been part of the *eight-stack*) are populated with EMPTY bricks, (3) on the surface of the sphere, empty cells are filled with BLACK bricks, and (4) on the surface of the sphere the IDENTITY brick is used leave non-empty cells (e.g., those that are part of the *eight-stack*) unchanged.

```
open Level 5;
val dimensions = 64;
val max = dimensions-1;
fun eight (x,y,z) =
let
val r = 5;
val numTthickness = 3;
val bgThickness = 3*r + 1;
in
ringY (r*3) bgThickness 10 [WHITE] (x,y,z);
ringY r numThickness 10 [BLACK] (x+r,y,z);
ringY r numThickness 10 [BLACK] (x-r,y,z)
end;
fun sphere radius (xCenter,yCenter,zCenter) =
let
fun brickFn(x,y,z) =
let
val x1 = Real.fromInt (x - xCenter);
val y1 = Real.fromInt (y - yCenter);
val z1 = Real.fromInt (z - zCenter);
val rSquared = x1*x1 + y1*y1 + z1*z1;
val r = Real.round(Math.sqrt(rSquared) );
val inSphere = radius >= r
andalso
r >= radius - 3;
in
if inSphere then
if access (x,y,z) = EMPTY then BLACK
else IDENTITY
else EMPTY
end;
in
traverseWithin (0,0,0)
(max,max,max)
brickFn
end;
fun eightBall (x,y,z) =
(
eight (x,0,z);
sphere 25 (x,y,z)
);
build(dimensions,dimensions,dimensions);
eightBall(30,30,30);
show "Eightball";
```

## Code-along Program 5

Bricklayer provides functions for creating a variety of geometric artifacts (including a function for creating a sphere). We can take advantage of this by positioning the 8 (of our 8-ball) on the xz-plane with y = 0.

We then call the Bricklayer function *hollowSphere* to create a black (hollow) sphere directly above the 8.

Next, we traverse the surface of the sphere and for each cell visited we access the corresponding cell in the xz-plane where the 8 is located. If the cell in the xz-plane is empty, we leave the cell in on the sphere unchanged; otherwise we replace the brick on the sphere with the corresponding brick found on the xz-plane.

And finally, we erase the 8 in the xz-plane and we are left with the 8 ball.

```
open Level_5;
val dimensions = 64;
val max = dimensions - 1;
fun eight (x,y,z) =
let
val r = 5;
val numThickness = 3;
val bgThickness = 3*r + 1;
in
ringY (r*3) bgThickness 1 [WHITE] (x,y,z);
ringY r numThickness 1 [BLACK] (x+r,y,z);
ringY r numThickness 1 [BLACK] (x-r,y,z)
end;
fun brickFn (x,y,z) =
let
val brickXZplane = access(x,0,z);
val brickSphere = access(x,y,z);
in
if brickSphere = EMPTY then EMPTY
else if brickXZplane = EMPTY then IDENTITY
else brickXZplane
end;
fun eightBall (x,y,z) =
(
eight (x,0,z);
hollowSphere 25 9 [BLACK] (x,y+1,z);
traverseWithin (0,1,0) (max,max,max) brickFn
);
build(dimensions,dimensions,dimensions);
eightBall(30,30,30);
show "Eightball";
```