xxxxxxxxxx
153
let a;
let b;
let ball = {};
const ballSpeed = 3;
let ballMult = {};
let ballPath = [];
function setup() {
createCanvas(600, 400);
// set Ellipse Diameters
a = width / 2 - 20;
b = height / 2 - 20;
// set ball initial position
ball = {
x: random(-a, a),
y: 0,
};
// vars to vary the angle of the ball direction
ballMult = {
x: random(-1, 1),
y: random(-1, 1),
};
// calculate focuses coordinates
let c = sqrt(a ** 2 - b ** 2);
focusA = { x: -c, y: 0 };
focusB = { x: c, y: 0 };
}
function draw() {
background(120);
// make canvas cartesian coordinates
translate(width / 2, height / 2);
scale(1, -1);
// Draw axes
stroke(255);
line(-width / 2, 0, width / 2, 0);
line(0, -height / 2, 0, height / 2);
// Draw Ellipse
noFill();
ellipse(0, 0, 2 * a, 2 * b);
// draw Focuces
fill(0);
stroke(0);
circle(focusA.x, focusA.y, 8);
circle(focusB.x, focusB.y, 8);
for (let s = 0; s < ballSpeed; s++) {
// Update ball position
ball.x += ballMult.x;
ball.y += ballMult.y;
// Draw ball
stroke(0);
fill(255, 0, 0);
circle(ball.x, ball.y, 8);
ballPath.push({ x: ball.x, y: ball.y });
noFill();
// Draw Ball Path
beginShape();
stroke(0);
for (let i = 0; i < ballPath.length; i++) {
vertex(ballPath[i].x, ballPath[i].y);
}
endShape();
// Calculate distance
distance = dist(ball.x, ball.y, focusA.x, focusA.y);
distance += dist(ball.x, ball.y, focusB.x, focusB.y);
if (ball.x > width / 2 || ball.x < -width / 2) {
ballMult.x *= -1;
}
if (ball.y > height / 2 || ball.y < -height / 2) {
ballMult.y *= -1;
}
// Check if ball hits the ellipse
if (distance >= 2 * a) {
// Draw distance
stroke(255, 255, 255, 50);
line(ball.x, ball.y, focusA.x, focusA.y);
line(ball.x, ball.y, focusB.x, focusB.y);
// Draw tangent Line
drawParametricLine(ball.x / a ** 2, ball.y / b ** 2, -1);
// Draw Normal Line
let A = ball.y / b ** 2;
let B = -(ball.x / a ** 2);
let C = -B * ball.y - A * ball.x;
drawParametricLine(A, B, C);
// Draw Path Line
let L =
(ballPath[ballPath.length - 1].y - ballPath[0].y) /
(ballPath[ballPath.length - 1].x - ballPath[0].x);
let M = -1;
let N = ballPath[0].y - L * ballPath[0].x;
drawParametricLine(L, M, N);
// Mirror path line over normal Line
let W = (2 * (A * L + M * B)) / (A ** 2 + B ** 2);
let P = L - A * W;
let Q = M - B * W;
let R = N - C * W;
drawParametricLine(P, Q, R);
//drawParametricSegment(P, Q, R, ball.x,width/2);
// So ball must follow the path of mirror Line
let slopeOld = ballMult.y / ballMult.x;
let slopeNew = -P / Q;
let angle = atan(-slopeNew);
s;
let Speed = sqrt(ballMult.x ** 2 + ballMult.y ** 2);
ballMult.x = Speed * cos(angle);
ballMult.y = Speed * sin(angle);
noLoop();
break;
}
}
}
function drawParametricLine(A, B, C) {
// Ax + By + C = 0
if (B) {
let x1 = -width / 2;
let y1 = -(A * x1 + C) / B;
let x2 = width / 2;
let y2 = -(A * x2 + C) / B;
line(x1, y1, x2, y2);
} else {
line(-C / A, -height / 2, -C / A, height / 2);
}
}
function drawParametricSegment(A, B, C, x1, x2) {
// Ax + By + C = 0
stroke(255, 0, 0);
if (B) {
let y1 = -(A * x1 + C) / B;
let y2 = -(A * x2 + C) / B;
line(x1, y1, x2, y2);
} else {
line(-C / A, y1, -C / A, y2);
}
}