- Week 1: Intern's Greetings!
- Week 2: Refining the MVP
- Week 3: Diving Into Shaders
- Week 4: From 2D to 3D
- Week 5: Back to Inspiration Images
- Week 6: Blended Approach
- Week 7: Restructuring the Project
- Week 8: Drawing Board

This week, I spent time planning a function that could be used to position objects in the room. For example, I might want to place two cubes around a plant, but they should never overlap with the plant or each other. When trying to understand this problem, I found this video by **Daniel Shiffman** very useful. That combined with pseudocode that Nikolai provided was the key to create some functions.

The pseudocode:

```
for (let i = 0; i < max; i++) {
outer: for (;;) {
let point = make_random_point();
for (let j = 0; j < i; j++) {
if (dist(locations[j], point) < limit) {
continue outer;
}
}
locations.push(point);
break;
}
}
```

We wanted to create arrays for the possible locations of objects, either around a circle or semicircle. There is a central object with some orbiting objects:

```
const locationsCircle = [];
const locationsHalfCircle = [];
function neighbour_location_circle({ cx, cy, cz, min, max, startAngle = 0, endAngle = 2 * Math.PI }) {
// distance from the object in the center
const distance = min + (max - min) * Math.random();
const angle = startAngle + (endAngle - startAngle) * Math.random();
return [cx + distance * Math.cos(angle), cy, cz + distance * Math.sin(angle)];
}
// how close to each other the orbiting objects can be
let limit = 6;
// number of positions to create
let numOfLoc = 3;
function dist(x1, x2, y1, y2) {
var a = x1 - x2;
var b = y1 - y2;
return Math.sqrt(a * a + b * b);
}
```

Creating positions for orbiting objects by using `limit`

and checking that they don't overlap:

```
for (let i = 0; i < numOfLoc; i++) {
outer: for (;;) {
let point = neighbour_location_circle({
cx: xLoc,
cy: yLoc,
cz: 5,
min: 15,
max: 25
});
for (let j = 0; j < i; j++) {
if (dist(locationsCircle[j][0], point[0], locationsCircle[j][2], point[2]) < limit) {
continue outer;
}
}
locationsCircle.push(point);
break;
}
}
// now we add spheres that orbit the box (as a circle)
for (let i = 0; i < numOfLoc; i++) {
const ballGeometry = new THREE.SphereGeometry(5, 5, 5);
const material = new THREE.MeshPhongMaterial({
color: 0xffffff,
emissive: 0x444444
});
const ball = new THREE.Mesh(ballGeometry, material);
ball.position.x = locationsCircle[i][0];
ball.position.y = locationsCircle[i][1];
ball.position.z = locationsCircle[i][2];
scene.add(ball);
}
```

For placing the objects in a semicircle (so that they don't end up inside a wall), we modify the start and end angle in the `neighbour_location_circle`

function:

```
for (let i = 0; i < numOfLoc; i++) {
outer: for (;;) {
let point = neighbour_location_circle({
cx: 45,
cy: 5,
cz: 5,
min: 15,
max: 25,
startAngle: Math.PI / 2,
endAngle: (3 / 2) * Math.PI
});
for (let j = 0; j < i; j++) {
if (dist(locationsCircle[j][0], point[0], locationsCircle[j][2], point[2]) < limit) {
continue outer;
}
}
locationsHalfCircle.push(point);
break;
}
}
```

## Adding New Data Points

It was also time to make the room visuals a bit more advanced. One of the elements of the room is a big blob that floats in the middle – a bit like a brain inside a head. Luckily, when working on my own art project on my free time, I had bumped into this resource about deformations with Perlin noise.

This animated blob is based on a vertex shader and fragment shader, added with a texture image. It's a good example on how to use normals and materials in deformations. An interesting thing with textures is that they can add a whole other dimension to the visual: you can use any image as a texture, and the shape will then reflect that image, hinting at a space or object that exists outside the viewport.

Finally, I spent time on the Python side of the app, adding a bunch of new variables that are based on the NLP calculations. The values that client side receives are now:

`avgTone`

`avgSubj`

`numOfMe`

(number of "I" and "me" words)`avgSentenceLength`

`numOfUnique`

(number of unique words)`interactionAmount`

(number of @ tags)`numOfNeg`

(number of negative tweets)`numOfPos`

`numOfNeutr`

`numOfAll`

I always enjoy exploring how easily Python can handle data. For example, I was prepared for requiring multiple lines of code to extract all the @ tags from an account. Finally it was just:

```
interactions = re.findall(r'@[\w\.-]+',str(whole_text_sample))
numOfInteractions = len(interactions)
```