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.
Original Processing.org Example: Reflection1
// All Examples Written by Casey Reas and Ben Fry // unless otherwise stated. float baseX1, baseY1, baseX2, baseY2; float baseLength; float[] xCoords, yCoords; float ellipseX, ellipseY, ellipseRadius = 6; float directionX, directionY; float ellipseSpeed = 3.5; float velocityX, velocityY; void setup(){ size(200, 200); frameRate(30); fill(128); smooth(); baseX1 = 0; baseY1 = height-150; baseX2 = width; baseY2 = height; // start ellipse at middle top of screen ellipseX = width/2; // calculate initial random direction directionX = random(0.1, 0.99); directionY = random(0.1, 0.99); // normalize direction vector float directionVectLength = sqrt(directionX*directionX + directionY*directionY); directionX /= directionVectLength; directionY /= directionVectLength; } void draw(){ // draw background fill(0, 12); noStroke(); rect(0, 0, width, height); // calculate length of base top baseLength = dist(baseX1, baseY1, baseX2, baseY2); xCoords = new float[ceil(baseLength)]; yCoords = new float[ceil(baseLength)]; // fill base top coordinate array for (int i=0; i<xCoords.length; i++){ xCoords[i] = baseX1 + ((baseX2-baseX1)/baseLength)*i; yCoords[i] = baseY1 + ((baseY2-baseY1)/baseLength)*i; } // draw base fill(200); quad(baseX1, baseY1, baseX2, baseY2, baseX2, height, 0, height); // calculate base top normal float baseDeltaX = (baseX2-baseX1)/baseLength; float baseDeltaY = (baseY2-baseY1)/baseLength; float normalX = -baseDeltaY; float normalY = baseDeltaX; // draw ellipse noFill(); stroke(200); ellipse(ellipseX, ellipseY, ellipseRadius*2, ellipseRadius*2); // calculate ellipse velocity velocityX = directionX * ellipseSpeed; velocityY = directionY * ellipseSpeed; // move elipse ellipseX += velocityX; ellipseY += velocityY; // normalized incidence vector float incidenceVectorX = -directionX; float incidenceVectorY = -directionY; // detect and handle collision for (int i=0; i<xCoords.length; i++){ // check distance between ellipse and base top coordinates if (dist(ellipseX, ellipseY, xCoords[i], yCoords[i]) < ellipseRadius){ // calculate dot product of incident vector and base top normal float dot = incidenceVectorX*normalX + incidenceVectorY*normalY; // calculate reflection vector float reflectionVectorX = 2*normalX*dot - incidenceVectorX; float reflectionVectorY = 2*normalY*dot - incidenceVectorY; // assign reflection vector to direction vector directionX = reflectionVectorX; directionY = reflectionVectorY; // draw base top normal at collision point stroke(255, 128, 0); line(ellipseX, ellipseY, ellipseX-normalX*100, ellipseY-normalY*100); } } // detect boundary collision // right if (ellipseX > width-ellipseRadius){ ellipseX = width-ellipseRadius; directionX *= -1; } // left if (ellipseX < ellipseRadius){ ellipseX = ellipseRadius; directionX *= -1; } // top if (ellipseY < ellipseRadius){ ellipseY = ellipseRadius; directionY *= -1; // randomize base top baseY1 = random(height-100, height); baseY2 = random(height-100, height); } }