// 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