*In which you learn how to navigate space and start implementing a utility class to represent locations and directions in 3D.*

Space is the stage on which visual programs tell their stories. In order to situate objects at particular locations, a program's space must have addresses. Physical spaces are addressed using streets and house numbers or latitudes and longitudes. Virtual spaces are frequently addressed using a Cartesian grid. A location on a Cartesian grid is a sequence of numbers describing how far the location is from some anchor point in the grid called the *origin*. These distances from the origin are called *coordinates*.

Three-dimensional Cartesian coordinates are often written in *vector* form:

$$ \begin{aligned} \text{origin} &= \begin{bmatrix}0 & 0 & 0\end{bmatrix} \\ \text{target} &= \begin{bmatrix}-5 & 8 & 2\end{bmatrix} \end{aligned} $$

Each individual number describes the distance from the origin along a single axis of the coordinate system. Different disciplines label these axes differently. This book follows these conventions, which are found in many computer graphics systems:

- The x-axis spans from left to right.
- The y-axis spans from bottom to top.
- The z-axis spans from beyond the screen to in front of the screen. That is, the positive z-axis points toward the viewer, not away from the viewer.

For example, the location \(\text{target}\) is -5 units left of the origin, 8 units above the origin, and 2 units in front of the origin.

You already know these terms because you have been dealing with Cartesian coordinate systems for many years. But now it's time to start programming with them.

Create a new file named `vector.js`

in a project and define a class named `Vector3`

:

```
export class Vector3 {
constructor(x, y, z) {
this.coordinates = [x, y, z];
}
toString() {
return `[${this.coordinates[0]}, ${this.coordinates[1]}, ${this.coordinates[2]}]`;
}
}
```

This book makes no attempt to teach you JavaScript. Read the code and work to understand it. Consult books, the web, and the humans around you if you have questions.

To test the constructor and `toString`

method, create another file named `test-vector.js`

and add this code:

```
import {Vector3} from './vector.js';
const vector = new Vector3(1, 2, 3);
console.log(vector.toString());
```

Run the tester in your terminal with this command:

`node test-vector.js`

A good vector class provides getters and setters for the individual coordinates. Place these definitions inside the `Vector3`

class:

```
get x() {
return this.coordinates[0];
}
get y() {
return this.coordinates[1];
}
get z() {
return this.coordinates[2];
}
set x(value) {
this.coordinates[0] = value;
}
set y(value) {
this.coordinates[1] = value;
}
set z(value) {
this.coordinates[2] = value;
}
```

These getters and setters make the class appear to have public instance variables named `x`

, `y`

, and `z`

. That way you can write code like this:

```
console.log(vector.x, vector.y, vector.z);
vector.x = 0;
vector.z = vector.y;
console.log(vector.x, vector.y, vector.z);
```

Append these lines to `test-vector.js`

and run the script.

These properties are just an illusion. Behind the scenes, `vector.x = 0`

turns into a setter function call.

In physics, a vector is a relative direction or offset. The starting location to which the vector is applied is not specified. A position, on the other hand, is an absolute location. In computer graphics, you might use a vector to represent the direction in which a player is jumping and a position to represent the player's current location.

Both vectors and positions are sequences of three numbers. Because of their similarity, your `Vector3`

class will serve both notions. Technically, some operations that you'll add to this class won't be supported by both types. But many graphics developers overlook their differences.

You will eventually need to be able to compute a vector's *magnitude*. Magnitude is the length of a straight line going from the origin to the vector's coordinates. In two dimensions, you have computed magnitude using the Pythagorean theorem. The x-coordinate is the length of one side, and the y-coordinate is the length of the other. The straight line is the hypotenuse, which has this length:

$$ \text{magnitude} = \sqrt{x^2 + y^2} $$

The Pythagorean theorem extends to three dimensions:

$$ \text{magnitude} = \sqrt{x^2 + y^2 + z^2} $$

This value is reasonably implemented with a getter:

```
get magnitude() {
return Math.sqrt(
this.coordinates[0] * this.coordinates[0] +
this.coordinates[1] * this.coordinates[1] +
this.coordinates[2] * this.coordinates[2]
);
}
```

Add this getter to your `Vector3`

class and add tests to print the magnitudes of the following vectors:

- \(\begin{bmatrix} 1 & 1 & 0 \end{bmatrix}\)
- \(\begin{bmatrix} 3 & 0 & 4 \end{bmatrix}\)
- \(\begin{bmatrix} 1 & 1 & 1 \end{bmatrix}\)
- \(\begin{bmatrix} -1 & -1 & -1 \end{bmatrix}\)
- \(\begin{bmatrix} 2 & 3 & 6 \end{bmatrix}\)

Reason about the results you see.

Though you recently added three setters to your `Vector3`

class, you are encouraged to keep your classes immutable as much as possible. That is, instead of mutating the state of an object, give back a new instance with the modified state. For example, this `invert`

function is mutable:

```
invert() {
this.coordinates[0] = -this.coordinates[0];
this.coordinates[1] = -this.coordinates[1];
this.coordinates[2] = -this.coordinates[2];
}
```

This `inverse`

function is immutable:

```
inverse() {
return new Vector3(-this.coordinates[0], -this.coordinates[1], -this.coordinates[2]);
}
```

Immutable classes are easier to depend on because they don't change in unpredictable ways. When you write code that relies on a mutable object, you must live in the fear that the object could change at any moment.

Add the following methods to your `Vector3`

class and test their results:

`add(that)`

, which returns a new `Vector3`

that is the sum of `this`

and `that`

. The parameter `that`

is assumed to be another `Vector3`

.
`scalarMultiply(scalar)`

, which returns a new `Vector3`

that is a scaled version of `this`

. Each coordinate is scaled, or multiplied, by `scalar`

.
`normalize()`

, which returns a new `Vector3`

in which each coordinate of `this`

is divided by the vector's magnitude. What is the magnitude of a normalized vector?
You could use your `Vector3`

class to define the `positions`

array in `hello-orange`

, like this perhaps:

```
const positions = [
new Vector3(0, 0, 0),
new Vector3(0.5, 0.5, 0.5),
];
```

This will fail, however, because the `VertexAttributes`

class expects a flat array of numbers. If you really want to use `Vector3`

, flatten the vectors using the `flatMap`

function:

```
const positions = [
new Vector3(0, 0, 0),
new Vector3(0.5, 0.5, 0),
].flatMap(vector => vector.coordinates);
```

You may want to study up on `flatMap`

if you haven't seen it before. Ignoring it and going with the original assignment to `positions`

is also fine.

Once you're done coding, commit and push your code to Git.