nine-point circle
bgColgColnGridgSpaceslopeafootxTmpxIntersectyIntersectdrawGrid
const bgCol = "#447abd";
const gCol = "#a2c2e8";
const nGrid = 20;
let w;
let gSpace;
function setup() {
w = max(500, min(windowWidth, windowHeight) * 0.9);
createCanvas(w, w);
describe(
"a triangle that changes slowly with a nine-point circle moving with it. Points are shown (midpoint, altitude foot, and midpoint with the vertex and orthocenter, and circle center). Blueprint design with drawing lines in a ligher weight."
);
gSpace = (w / nGrid) * 0.95;
rectMode(CENTER);
angleMode(DEGREES);
textSize(16);
}
function draw() {
background(bgCol);
translate(w / 2, w / 2);
t = frameCount / 3;
drawGrid();
stroke(255);
strokeWeight(1);
pt1 = {
x: -5 * gSpace - 3 * gSpace * cos(t),
y: -5 * gSpace - 3 * gSpace * cos(t)
};
pt2 = {
x: -3 * gSpace - 4 * gSpace * cos(t / 2),
y: 5 * gSpace - 2 * gSpace * cos(t / 2)
};
pt3 = {
x: 5 * gSpace - 3 * gSpace * cos(t / 3),
y: -2 * gSpace - 5 * gSpace * cos(t / 3)
};
mp1 = {
x: (pt2.x + pt1.x) / 2,
y: (pt2.y + pt1.y) / 2
};
mp2 = {
x: (pt1.x + pt3.x) / 2,
y: (pt1.y + pt3.y) / 2
};
mp3 = {
x: (pt3.x + pt2.x) / 2,
y: (pt3.y + pt2.y) / 2
};
function slope(p1, p2) {
return (p1.y - p2.y) / (p1.x - p2.x);
}
m1 = slope(pt1, pt2);
m2 = slope(pt1, pt3);
m3 = slope(pt2, pt3);
function afoot(m, vp, lp) {
let x = (lp.y - vp.y - ((1 / m) * vp.x + m * lp.x)) / (-1 / m - m);
let y = m * (x - lp.x) + lp.y;
return { x: x, y: y };
}
altFoot1 = afoot(m1, pt3, pt1);
altFoot2 = afoot(m2, pt2, pt1);
altFoot3 = afoot(m3, pt1, pt2);
strokeWeight(1);
line(pt3.x, pt3.y, altFoot1.x, altFoot1.y);
line(pt2.x, pt2.y, altFoot2.x, altFoot2.y);
line(pt1.x, pt1.y, altFoot3.x, altFoot3.y);
let xTmp =
(pt2.y - pt3.y + (1 / m2) * pt2.x - (1 / m1) * pt3.x) / (1 / m2 - 1 / m1);
ortho1 = { x: xTmp, y: (-1 / m1) * (xTmp - pt3.x) + pt3.y };
mpo1 = { x: (ortho1.x + pt1.x) / 2, y: (ortho1.y + pt1.y) / 2 };
mpo2 = { x: (ortho1.x + pt2.x) / 2, y: (ortho1.y + pt2.y) / 2 };
mpo3 = { x: (ortho1.x + pt3.x) / 2, y: (ortho1.y + pt3.y) / 2 };
let s1 = -1 / m1;
let s2 = -1 / m2;
let s3 = -1 / m3;
let xIntersect = (mp1.y - mp2.y - s1 * mp1.x + s2 * mp2.x) / (s2 - s1);
let yIntersect = s1 * (xIntersect - mp1.x) + mp1.y;
circum = { x: xIntersect, y: yIntersect };
cent = { x: (circum.x + ortho1.x) / 2, y: (circum.y + ortho1.y) / 2 };
strokeWeight(0.5);
line(
-w / 3,
s1 * (-w / 3 - mp1.x) + mp1.y,
w / 3,
s1 * (w / 3 - mp1.x) + mp1.y
);
line(
-w / 3,
s2 * (-w / 3 - mp2.x) + mp2.y,
w / 3,
s2 * (w / 3 - mp2.x) + mp2.y
);
line(
-w / 3,
s3 * (-w / 3 - mp3.x) + mp3.y,
w / 3,
s3 * (w / 3 - mp3.x) + mp3.y
);
fill(gCol);
circle(ortho1.x, ortho1.y, 6);
circle(cent.x, cent.y, 6);
circle(circum.x, circum.y, 6);
noFill();
strokeWeight(2);
circle(cent.x, cent.y, 2 * dist(cent.x, cent.y, mp1.x, mp1.y));
triangle(pt1.x, pt1.y, pt2.x, pt2.y, pt3.x, pt3.y);
circle(mp1.x, mp1.y, 10);
circle(mp2.x, mp2.y, 10);
circle(mp3.x, mp3.y, 10);
circle(mpo1.x, mpo1.y, 10);
circle(mpo2.x, mpo2.y, 10);
circle(mpo3.x, mpo3.y, 10);
circle(altFoot1.x, altFoot1.y, 10);
circle(altFoot2.x, altFoot2.y, 10);
circle(altFoot3.x, altFoot3.y, 10);
noStroke();
fill(gCol);
text("nine-point circle", -w / 2 + 10, w / 2 - 10);
}
function drawGrid() {
stroke(gCol);
strokeWeight(0.3);
for (let i = 1; i <= nGrid; i++) {
for (let j = 1; j <= nGrid; j++) {
line(
-w / 2 + gSpace * i,
-w / 2 + gSpace,
-w / 2 + gSpace * i,
w / 2 - gSpace
);
line(
-w / 2 + gSpace,
-w / 2 + gSpace * i,
w / 2 - gSpace,
-w / 2 + gSpace * i
);
}
}
noFill();
strokeWeight(3);
rect(0, 0, w - 2 * gSpace);
}
function mousePressed() {
setup();
draw();
}
function windowResized() {
setup();
draw();
}