// James Brink, 7/2/2020
// bezier
let cnvs;
let cnt;
let pts = [];
let pts2 = [];
let clearBtn;
let showPtsBtn;
let showTanBtn;
let showGenerate;
let mouseDown = false;
let mouseStr = "";
let mouseStr2 = "";
let movingPt = null;
let movingPt2 = null;
let imgHeart;
let imgFlower;
let imgSleigh
function preload() {
imgHeart = loadImage("heart.png");
imgFlower = loadImage("flower.png");
imgSleigh = loadImage("sleigh.png");
}
/**
* setup
*/
function setup() {
setupTopCanvas();
setupMiddleCanvas();
} // setup
/**
* draw
*/
function draw() {
cnvs.background(240, 240, 240);
drawTopCanvas();
drawMiddleCanvas();
} // draw
/**
* setupTopCanvas
*/
function setupTopCanvas() {
// *** top canvas ***
cnvs = createCanvasClass(500, 360);
cnvs.parent("top");
span = createSpan("
");
span.parent("top");
clearBtn = createButton("Clear");
clearBtn.parent("top");
clearBtn.mouseClicked(clearPoints);
showPtsBtn = makeCheckbox("Show points", false, "top");
showTanBtn = makeCheckbox("Show tangents", false, "top");
showGenerate = makeCheckbox("Show generate", false, "top");
pts[0] = [170, 40];
pts[1] = [20, 20];
pts[2] = [180, 180];
pts[3] = [30, 160];
cnvs.mousePressed(down);
cnvs.mouseReleased(up);
cnvs.mouseMoved(moved);
} // setupTopCanvas
/**
* drawTopCanvas
*/
function drawTopCanvas() {
cnvs.noStroke();
for (let i = 0; i < pts.length; i++) {
if (i % 3 == 0) {
cnvs.fill(0, 0, 255);
cnvs.ellipse(pts[i][0], pts[i][1], 7);
} else {
cnvs.fill(0, 180, 0);
cnvs.rect(pts[i][0]-2, pts[i][1]-2, 7, 7)
}
}
cnvs.stroke(0, 196, 0);
for (let i = 1; i < pts.length; i += 2) {
cnvs.line(pts[i-1][0], pts[i-1][1], pts[i][0], pts[i][1]);
}
if (pts.length > 3) {
cnvs.stroke(255, 0, 0);
cnvs.fill(255, 255, 0);
cnvs.bezier(pts[0][0], pts[0][1], pts[1][0], pts[1][1], pts[2][0], pts[2][1],
pts[3][0], pts[3][1] );
let steps = 10;
if (showPtsBtn.checked()) {
drawPoints(steps);
}
if (showTanBtn.checked()) {
drawTangents(steps);
}
if (showGenerate.checked()) {
drawGenerate();
}
}
cnvs.noStroke();
cnvs.fill(255, 0, 255);
cnvs.textSize(18);
cnvs.text("Bezier Curve", 390, 20);
cnvs.textSize(14);
cnvs.text("Controlling points", 390, 40);
for (let i = 0; i < pts.length; i++) {
if (i % 3 == 0) {
cnvs.fill(0, 0, 255);
} else {
cnvs.fill(0, 180, 0);
}
cnvs.text("(" + pts[i][0] + "," + pts[i][1] + ")", 420, 60 + 19 * i);
}
if (movingPt != null) {
pts[movingPt] = [cnvs.mouseX, cnvs.mouseY];
}
cnvs.text(mouseStr, 10, 355);
} // drawTopCanvas
/**
* moved
*/
function moved() {
mouseStr = "(" + cnvs.mouseX + ", " + cnvs.mouseY + ")";
} // moved
/**
* clearPoints
*/
function clearPoints() {
pts = [];
} // clearPoints
/**
* down
*/
function down() {
let len = pts.length;
for (let j = 0; j < len; j++) {
if (dist(cnvs.mouseX, cnvs.mouseY, pts[j][0], pts[j][1]) < 7) {
movingPt = j;
return;
}
}
if (len < 4) {
pts[len] = [cnvs.mouseX, cnvs.mouseY];
}
} // down
/**
* up
*/
function up() {
movingPt = null;
} // up
function drawPoints(steps) {
if (showPtsBtn.checked()) {
cnvs.fill(255, 0, 0);
cnvs.noStroke();
for (let i = 0; i <= steps; i++) {
let t = i / steps;
let x = bezierPoint(pts[0][0], pts[1][0], pts[2][0], pts[3][0], t);
let y = bezierPoint(pts[0][1], pts[1][1], pts[2][1], pts[3][1], t);
cnvs.noFill();
cnvs.stroke(255, 0, 0);
cnvs.ellipse(x, y, 7, 7);
cnvs.fill(255, 0, 0);
cnvs.noStroke();
cnvs.text("(" + round(100*x)/100 + "," + round(100*y)/100 + ")",
400, 160 + 19 * i);
}
}
} // drawPoints
function drawTangents(steps) {
cnvs.stroke(0, 128, 255);
for (let i = 0; i <= steps; i++) {
let t = i / steps;
// Get the location of the point
let x = bezierPoint(pts[0][0], pts[1][0], pts[2][0], pts[3][0], t);
let y = bezierPoint(pts[0][1], pts[1][1], pts[2][1], pts[3][1], t);
// Get the tangent points
let tx = bezierTangent(pts[0][0], pts[1][0], pts[2][0], pts[3][0], t);
let ty = bezierTangent(pts[0][1], pts[1][1], pts[2][1], pts[3][1], t);
// Calculate an angle from the tangent points
let a = atan2(ty, tx);
a += PI;
stroke(255, 102, 0);
cnvs.line(x, y, cos(a) * 40 + x, sin(a) * 40 + y);
// The following line of code makes a line
// inverse of the above line
//cnvs.line(x, y, cos(a)*-30 + x, sin(a)*-30 + y);
}
} // drawTangents
/**
* drawGenerate
*/
function drawGenerate() {
cnvs.stroke(0, 255, 255);
let x1 = pts[0][0];
let y1 = pts[0][1];
let x2 = pts[1][0];
let y2 = pts[1][1];
let x3 = pts[2][0];
let y3 = pts[2][1];
let x4 = pts[3][0];
let y4 = pts[3][1];
cnvs.line(x2, y2, x3, y3);
let t = (frameCount % 600)/600;
{
let xx1, yy1, xx2, yy2, xx3, yy3, xxx1, yyy1, xxx2, yyy2, xxxx, yyyy;
xx1 = x1 * (1 - t) + x2 * t;
yy1 = y1 * (1 - t) + y2 * t;
xx2 = x2 * (1 - t) + x3 * t;
yy2 = y2 * (1 - t) + y3 * t;
xx3 = x3 * (1 - t) + x4 * t;
yy3 = y3 * (1 - t) + y4 * t;
cnvs.stroke(255, 0, 255);
cnvs.line(xx1, yy1, xx2, yy2);
cnvs.line(xx2, yy2, xx3, yy3);
xxx1 = xx1 * (1 - t) + xx2 * t;
yyy1 = yy1 * (1 - t) + yy2 * t;
xxx2 = xx2 * (1 - t) + xx3 * t;
yyy2 = yy2 * (1 - t) + yy3 * t;
cnvs.stroke(128, 0, 128);
cnvs.line(xxx1, yyy1, xxx2, yyy2);
cnvs.fill(0, 0, 255);
xxxx = xxx1 * (1 - t) + xxx2 * t;
yyyy = yyy1 * (1 - t) + yyy2 * t;
cnvs.ellipse(xxxx, yyyy, 7);
cnvs.fill(255, 140, 0);
cnvs.noStroke();
cnvs.ellipse(xx1, yy1, 7) ;
cnvs.ellipse(xx2, yy2, 7);
cnvs.ellipse(xx3, yy3, 7);
cnvs.ellipse(xxx1, yyy1, 7);
cnvs.ellipse(xxx2, yyy2, 7)
}
} // drawGenerate
/**
* setupMiddleCanvas
*/
function setupMiddleCanvas() {
cnvs2 = createCanvasClass(500, 360);
cnvs2.parent("middle");
// let imgHeart = document.getElementById("heart");
// imgFlower = document.getElementById("flower");
// imgSleigh = document.getElementById("sleigh");
span2 = createSpan("
");
span2.parent("middle");
clearBtn2 = createButton("Clear");
clearBtn2.parent("middle");
clearBtn2.mouseClicked(clearPoints2);
radio = createRadio()
radio.parent("middle");
radio.style("display: inline-block");
radio.option("Smooth", 1);
radio.option("Corners", 2);
radio.value("1"); // the value has to be a string
fillBtn2 = makeCheckbox("Fill", false, "middle");
hideControlsBtn2 = makeCheckbox("Hide Controls", false, "middle");
hideAnchorsBtn2 = makeCheckbox("HideAnchors", false, "middle");
span4 = createSpan("
");
span4.parent("middle");
showHeartBtn2 = makeCheckbox("Show heart", true, "middle");
showFlowerBtn2 = makeCheckbox("Show flower", false, "middle");
showSleighBtn2 = makeCheckbox("Show Santa's sleigh", false, "middle");
deleteBtn2 = createButton("Delete last point");
deleteBtn2.parent("middle");
deleteBtn2.mouseClicked(deletePoint2);
lastAnchor = -1;
pts2[0] = [167,87];
pts2[1] = [156, 52];
pts2[2] = [88, 37];
pts2[3] = [47, 81];
pts2[4] = [23, 116];
pts2[5] = [38, 165]
pts2[6] = [83, 196];
cnvs2.mousePressed(down2);
cnvs2.mouseReleased(up2);
cnvs2.mouseMoved(moved2);
} // setupMiddleCanvas
/**
* drawMiddleCanvas
*/
function drawMiddleCanvas() {
cnvs2.background(240, 240, 240);
if (showHeartBtn2.checked()) {
cnvs2.image(imgHeart, 30, 30);
cnvs2.fill(240, 240, 240, 220);
cnvs2.rect(30, 30, 277, 266);
}
if (showFlowerBtn2.checked()) {
cnvs2.image(imgFlower, 30, 30);
cnvs2.fill(240, 240, 240, 220);
cnvs2.rect(30, 30, 277, 266);
}
if (showSleighBtn2.checked()) {
cnvs2.image(imgSleigh, 30, 30);
cnvs2.fill(0, 240, 240, 220);
cnvs2.rect(30, 30, 300, 203);
}
cnvs.noStroke();
for (let i = 0; i < pts2.length; i++) {
if (i % 3 == 0) {
if (!hideAnchorsBtn2.checked()) {
cnvs2.fill(0, 0, 255);
cnvs2.ellipse(pts2[i][0], pts2[i][1], 7);
}
} else if (!hideControlsBtn2.checked()){
cnvs2.fill(0, 180, 0);
cnvs2.rect(pts2[i][0]-2, pts2[i][1]-2, 6, 6)
}
}
if (!hideControlsBtn2.checked()) {
cnvs2.stroke(0, 196, 0);
for (let i = 0; i 3) {
cnvs2.stroke(255, 0, 0);
if (fillBtn2.checked()) {
cnvs2.fill(255, 255, 0);
} else {
cnvs2.noFill();
}
cnvs2.bezier(pts2[i-3][0], pts2[i-3][1], pts2[i-2][0], pts2[i-2][1],
pts2[i-1][0], pts2[i-1][1], pts2[i][0], pts2[i][1] );
lastAnchor = i;
}
cnvs2.noStroke();
cnvs2.fill(255, 0, 255);
cnvs2.textSize(16);
cnvs2.text("Bezier Curve", 390, 20);
cnvs2.textSize(12);
cnvs2.text("Controlling points", 390, 38);
for (let i = 0; i < pts2.length; i++) {
if (i % 3 == 0) {
cnvs2.fill(0, 0, 255);
} else {
cnvs2.fill(0, 180, 0);
}
cnvs2.text("(" + pts2[i][0] + "," + pts2[i][1] + ")", 420, 56 + 17 * i);
}
if (movingPt2 != null) {
pts2[movingPt2] = [cnvs2.mouseX, cnvs2.mouseY];
}
cnvs2.text(mouseStr2, 10, 355);
} // drawMiddleCanvas
/**
* moved2
*/
function moved2() {
mouseStr2 = "(" + cnvs2.mouseX + ", " + cnvs2.mouseY + ")";
} // moved
/**
* clearPoints2
*/
function clearPoints2() {
lastAnchor = -1;
pts2 = [];
} // clearPoints
/**
* down2
*/
function down2() {
let len = pts2.length;
for (let j = 0; j < len; j++) {
if (dist(cnvs2.mouseX, cnvs2.mouseY, pts2[j][0], pts2[j][1]) < 7) {
movingPt2 = j;
return;
}
}
if (radio.value() == "1" &&
pts2.length >= 4 && lastAnchor == len - 1 ) {
let last = len - 1;
pts2[len] = [ 2 * pts2[last][0] - pts2[last-1][0],
2 * pts2[last][1] - pts2[last-1][1]];
}
pts2[pts2.length] = [cnvs2.mouseX, cnvs2.mouseY];
} // down2
/**
* up2
*/
function up2() {
movingPt2 = null;
} // up2
function deletePoint2() {
if (pts2.length > 0) {
pts2.pop();
}
}
function makeCheckbox(label, isChecked, itsParent) {
let space = createSpan(" ");
space.parent(itsParent);
let chk = createCheckbox(label, isChecked);
chk.parent(itsParent);
chk.style("display: inline-block")
return chk;
} // makeCheckbox