# Non-orthogonal Reflection

Non-orthogonal Reflection by Ira Greenberg.

Based on the equation (R = 2N(N*L)-L) where R is the reflection vector, N is the normal, and L is the incident vector.

```
// Position of left hand side of floor
PVector base1;
// Position of right hand side of floor
PVector base2;
// Length of floor
float baseLength;

// An array of subpoints along the floor path
PVector[] coords;

// Variables related to moving ball
PVector position;
PVector velocity;
float r = 6;
float speed = 3.5;

void setup() {
size(640, 360);

fill(128);
base1 = new PVector(0, height-150);
base2 = new PVector(width, height);
createGround();

// start ellipse at middle top of screen
position = new PVector(width/2, 0);

// calculate initial random velocity
velocity = PVector.random2D();
velocity.mult(speed);
}

void draw() {
// draw background
fill(0, 12);
noStroke();
rect(0, 0, width, height);

// draw base
fill(200);
quad(base1.x, base1.y, base2.x, base2.y, base2.x, height, 0, height);

// calculate base top normal
PVector baseDelta = PVector.sub(base2, base1);
baseDelta.normalize();
PVector normal = new PVector(-baseDelta.y, baseDelta.x);

// draw ellipse
noStroke();
fill(255);
ellipse(position.x, position.y, r*2, r*2);

// move elipse

// normalized incidence vector
PVector incidence = PVector.mult(velocity, -1);
incidence.normalize();

// detect and handle collision
for (int i=0; i<coords.length; i++) {
// check distance between ellipse and base top coordinates
if (PVector.dist(position, coords[i]) < r) {

// calculate dot product of incident vector and base top normal
float dot = incidence.dot(normal);

// calculate reflection vector
// assign reflection vector to direction vector
velocity.set(2*normal.x*dot - incidence.x, 2*normal.y*dot - incidence.y, 0);
velocity.mult(speed);

// draw base top normal at collision point
stroke(255, 128, 0);
line(position.x, position.y, position.x-normal.x*100, position.y-normal.y*100);
}
}

// detect boundary collision
// right
if (position.x > width-r) {
position.x = width-r;
velocity.x *= -1;
}
// left
if (position.x < r) {
position.x = r;
velocity.x *= -1;
}
// top
if (position.y < r) {
position.y = r;
velocity.y *= -1;
// randomize base top
base1.y = random(height-100, height);
base2.y = random(height-100, height);
createGround();
}
}

// Calculate variables for the ground
void createGround() {
// calculate length of base top
baseLength = PVector.dist(base1, base2);

// fill base top coordinate array
coords = new PVector[ceil(baseLength)];
for (int i=0; i<coords.length; i++) {
coords[i] = new PVector();
coords[i].x = base1.x + ((base2.x-base1.x)/baseLength)*i;
coords[i].y = base1.y + ((base2.y-base1.y)/baseLength)*i;
}
}

```

## Functions Used

ellipse()

Draws an ellipse (oval) to the screen

set()

Changes the color of any pixel, or writes an image directly to the display window

fill()

Sets the color used to fill shapes

size()

Defines the dimension of the display window width and height in units of pixels

rect()

Draws a rectangle to the screen

random()

Generates random numbers

. (dot)

line()

Draws a line (a direct path between two points) to the screen

stroke()

Sets the color used to draw lines and borders around shapes

setup()

The setup() function is run once, when the program starts

draw()

Called directly after setup(), the draw() function continuously executes the lines of code contained inside its block until the program is stopped or noLoop() is called

ceil()

Calculates the closest int value that is greater than or equal to the value of the parameter

noStroke()

Disables drawing the stroke (outline)