diff --git a/html_to_astro.ipynb b/html_to_astro.ipynb index 226c13a2d..16b41ded6 100644 --- a/html_to_astro.ipynb +++ b/html_to_astro.ipynb @@ -261,72 +261,63 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 68, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\n" + "\n" ] } ], "source": [ "e = r\"\"\"\n", - "\\[\n", - "\\int_0^t a_1(t) \\,d\\tau\n", - "= \\left[a_1(t) \\, \\tau\\right]_{\\tau = 0}^{\\tau = t}\n", - "= a_1(t) \\, t,\n", - " \\]\n", + "\\[\\begin{aligned}\n", + "x = u, \\quad \\quad y = y(u) = y(x)\n", + "\\end{aligned}\\]\n", "\"\"\"\n", "\n", - "print(\"\")\n" + "print(\"\")\n" ] }, { "cell_type": "code", - "execution_count": 74, + "execution_count": 66, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\\\\begin{aligned}\\\\vec{r} &= r \\\\,\\\\hat{e}_r \\\\\\\\\\\\vec{v} &= \\\\dot{r} \\\\,\\\\hat{e}_r+ r \\\\dot\\\\theta \\\\sin\\\\phi \\\\,\\\\hat{e}_{\\\\theta}+ r \\\\dot\\\\phi \\\\,\\\\hat{e}_{\\\\phi} \\\\\\\\\\\\vec{a} &= (\\\\ddot{r} - r \\\\dot{\\\\theta}^2 \\\\sin^2\\\\phi- r \\\\dot{\\\\phi}^2) \\\\,\\\\hat{e}_r \\\\\\\\&\\\\quad + (r \\\\ddot\\\\theta \\\\sin\\\\phi+ 2 \\\\dot{r} \\\\dot\\\\theta \\\\sin\\\\phi+ 2 r \\\\dot\\\\theta \\\\dot\\\\phi \\\\cos\\\\phi) \\\\,\\\\hat{e}_{\\\\theta} \\\\\\\\&\\\\quad + (r \\\\ddot\\\\phi + 2 \\\\dot{r} \\\\dot\\\\phi- r \\\\dot{\\\\theta}^2 \\\\sin\\\\phi \\\\cos\\\\phi) \\\\,\\\\hat{e}_{\\\\phi}\\\\end{aligned}\n" + "\\\\kappa = \\\\frac{|y''(x)|}{(1 + y'(x)^2)^{3/2}}\n" ] } ], "source": [ - "print(e.replace('\\n', '').replace(' ', '').replace(\"\\\\\", r\"\\\\\"))" + "print(e.replace('\\n', '').replace(' ', '').replace('$', '').replace(r'\\[', '').replace(r'\\]', '').replace(\"\\\\\", r\"\\\\\"))" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": 16, + "execution_count": 69, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\n" + "\n" ] } ], "source": [ "e = r\"\"\"\n", - "$\\vec{a}(t)$\n", + "$x'(u) = 1$\n", "\"\"\"\n", "\n", - "print(\"\")" + "print(\"\")" ] }, { @@ -334,6 +325,11 @@ "metadata": {}, "source": [] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, { "cell_type": "markdown", "metadata": {}, diff --git a/public/dyn/particle_kinematics/canvases.js b/public/dyn/particle_kinematics/canvases.js new file mode 100644 index 000000000..d2ae4f48e --- /dev/null +++ b/public/dyn/particle_kinematics/canvases.js @@ -0,0 +1,717 @@ + +$(document).ready(function() { + + rkr_fc_c = new PrairieDrawAnim("rkr-fc-c", function(t) { + this.setUnits(4.5, 3); + + this.addOption("showLabels", true); + this.addOption("showAngVel", true); + this.addOption("axis", "k"); + this.addOption("showVectors", false); + + var O = $V([0, 0, 0]); + var rX = $V([1, 0, 0]); + var rY = $V([0, 1, 0]); + var rZ = $V([0, 0, 1]); + var gS = 2; // ground size + + var theta = t - 0.5 * Math.sin(t); + var omega = 1 - 0.5 * Math.cos(t); + + var axis; + if (this.getOption("axis") === "i") { + axis = Vector.i; + } else if (this.getOption("axis") === "j") { + axis = Vector.j; + } else if (this.getOption("axis") === "k") { + axis = Vector.k; + } else if (this.getOption("axis") === "ij") { + axis = Vector.i.add(Vector.j); + } else if (this.getOption("axis") === "ijk") { + axis = Vector.i.add(Vector.j).add(Vector.k); + } + + var omegaVec = axis.toUnitVector().x(omega); + + var splitLine = function(p1, p2, type, drawAbove) { + var above = [], below = []; + if (p1.e(3) >= 0 && p2.e(3) >= 0) { + above = [p1, p2]; + } else if (p1.e(3) <= 0 && p2.e(3) <= 0) { + below = [p1, p2]; + } else { + var alpha = p1.e(3) / (p1.e(3) - p2.e(3)); + var p3 = p1.x(1 - alpha).add(p2.x(alpha)); + if (p1.e(3) >= 0) { + above = [p1, p3]; + below = [p3, p2]; + } else { + above = [p3, p2]; + below = [p1, p3]; + } + } + if (drawAbove) { + if (above.length === 2) { + this.line(above[0], above[1], type); + } + } else { + if (below.length === 2) { + this.line(below[0], below[1], type); + } + } + }.bind(this); + + var cube = {}; + cube["000"] = $V([-1, -1, -1]).rotate(theta, $L(O, axis)); + cube["001"] = $V([-1, -1, 1]).rotate(theta, $L(O, axis)); + cube["010"] = $V([-1, 1, -1]).rotate(theta, $L(O, axis)); + cube["011"] = $V([-1, 1, 1]).rotate(theta, $L(O, axis)); + cube["100"] = $V([ 1, -1, -1]).rotate(theta, $L(O, axis)); + cube["101"] = $V([ 1, -1, 1]).rotate(theta, $L(O, axis)); + cube["110"] = $V([ 1, 1, -1]).rotate(theta, $L(O, axis)); + cube["111"] = $V([ 1, 1, 1]).rotate(theta, $L(O, axis)); + + if (this.getOption("showVectors")) { + for (var c in cube) { + if (cube[c].e(3) < 0) { + this.arrow(O, cube[c], "position"); + } + } + } + + splitLine(cube["000"], cube["001"], undefined, false); + splitLine(cube["010"], cube["011"], undefined, false); + splitLine(cube["100"], cube["101"], undefined, false); + splitLine(cube["110"], cube["111"], undefined, false); + splitLine(cube["000"], cube["010"], undefined, false); + splitLine(cube["010"], cube["110"], undefined, false); + splitLine(cube["110"], cube["100"], undefined, false); + splitLine(cube["100"], cube["000"], undefined, false); + splitLine(cube["001"], cube["011"], undefined, false); + splitLine(cube["011"], cube["111"], undefined, false); + splitLine(cube["111"], cube["101"], undefined, false); + splitLine(cube["101"], cube["001"], undefined, false); + + var groundBorder = [$V([-gS, -gS, 0]), $V([-gS, gS, 0]), $V([gS, gS, 0]), $V([gS, -gS, 0])]; + var groundAlpha = 0.8; + this.save(); + this.setProp("shapeInsideColor", "rgba(255, 255, 255, " + groundAlpha + ")"); + this.polyLine(groundBorder, true, true); + this.restore(); + + var nGrid = 3; + for (var i = -nGrid; i <= nGrid; i++) { + this.line($V([i / nGrid * gS, -gS, 0]), $V([i / nGrid * gS, gS, 0]), "grid"); + this.line($V([-gS, i / nGrid * gS, 0]), $V([gS, i / nGrid * gS, 0]), "grid"); + } + var faceLine = function(points) { + var line = []; + var lastPoint = points[3]; + var lastAbove = (lastPoint.e(3) > 0); + for (var i = 0; i < 4; i++) { + var above = (points[i].e(3) > 0); + if (above !== lastAbove) { + var alpha = this.linearDeinterp(points[i].e(3), lastPoint.e(3), 0); + line.push(this.linearInterpVector(points[i], lastPoint, alpha)); + } + lastPoint = points[i]; + lastAbove = above; + } + if (line.length === 2) { + this.line(line[0], line[1], "grid"); + } + }.bind(this); + + faceLine([cube["000"], cube["001"], cube["011"], cube["010"]]); + faceLine([cube["100"], cube["101"], cube["111"], cube["110"]]); + faceLine([cube["000"], cube["001"], cube["101"], cube["100"]]); + faceLine([cube["010"], cube["011"], cube["111"], cube["110"]]); + faceLine([cube["000"], cube["010"], cube["110"], cube["100"]]); + faceLine([cube["001"], cube["011"], cube["111"], cube["101"]]); + + this.polyLine(groundBorder, true, false); + this.arrow(O, rX); + this.arrow(O, rY); + this.arrow(O, rZ); + if (this.getOption("showLabels")) { + this.labelLine(O, rX, $V([1, -1]), "TEX:$x$"); + this.labelLine(O, rY, $V([1, 1]), "TEX:$y$"); + this.labelLine(O, rZ, $V([1, 1]), "TEX:$z$"); + } + + if (this.getOption("showVectors")) { + for (var c in cube) { + if (cube[c].e(3) >= 0) { + this.arrow(O, cube[c], "position"); + } + } + } + + splitLine(cube["000"], cube["001"], undefined, true); + splitLine(cube["010"], cube["011"], undefined, true); + splitLine(cube["100"], cube["101"], undefined, true); + splitLine(cube["110"], cube["111"], undefined, true); + splitLine(cube["000"], cube["010"], undefined, true); + splitLine(cube["010"], cube["110"], undefined, true); + splitLine(cube["110"], cube["100"], undefined, true); + splitLine(cube["100"], cube["000"], undefined, true); + splitLine(cube["001"], cube["011"], undefined, true); + splitLine(cube["011"], cube["111"], undefined, true); + splitLine(cube["111"], cube["101"], undefined, true); + splitLine(cube["101"], cube["001"], undefined, true); + + if (this.getOption("showAngVel")) { + this.arrow(O, omegaVec, "angVel"); + if (this.getOption("showLabels")) { + this.labelLine(O, omegaVec, $V([1, 1]), "TEX:$\\vec{\\omega}$"); + } + } + + }); + + rkr_fc_c.activate3DControl(); + + rkr_fe_c = new PrairieDrawAnim("rkr-fe-c", function(t) { + this.setUnits(4.5, 3); + + this.addOption("showLabels", true); + this.addOption("showVelocity", false); + + var O = $V([0, 0, 0]); + var rX = $V([1, 0, 0]); + var rY = $V([0, 1, 0]); + var rZ = $V([0, 0, 1]); + var gS = 2; // ground size + + var theta = 1.2 * Math.sin(t); + var omega = 1.2 * Math.cos(t); + var omegaVec = $V([0, 0, omega]); + + var p = $V([1.2, 0, 0]).rotate(theta, $L(O, Vector.k)); + var v = omegaVec.cross(p); + + if (omegaVec.e(3) < 0) { + this.arrow(O, omegaVec, "angVel"); + this.labelLine(O, omegaVec, $V([1, 1]), "TEX:$\\vec{\\omega}$"); + } + + var groundBorder = [$V([-gS, -gS, 0]), $V([-gS, gS, 0]), $V([gS, gS, 0]), $V([gS, -gS, 0])]; + var groundAlpha = 0.8; + this.save(); + this.setProp("shapeInsideColor", "rgba(255, 255, 255, " + groundAlpha + ")"); + this.polyLine(groundBorder, true, true); + this.restore(); + + var nGrid = 3; + for (var i = -nGrid; i <= nGrid; i++) { + this.line($V([i / nGrid * gS, -gS, 0]), $V([i / nGrid * gS, gS, 0]), "grid"); + this.line($V([-gS, i / nGrid * gS, 0]), $V([gS, i / nGrid * gS, 0]), "grid"); + } + this.polyLine(groundBorder, true, false); + this.arrow(O, rX); + this.arrow(O, rY); + this.arrow(O, rZ); + if (this.getOption("showLabels")) { + this.labelLine(O, rX, $V([1, -1]), "TEX:$x$"); + this.labelLine(O, rY, $V([1, 1]), "TEX:$y$"); + this.labelLine(O, rZ, $V([1, 1]), "TEX:$z$"); + } + + if (omegaVec.e(3) >= 0) { + this.arrow(O, omegaVec, "angVel"); + this.labelLine(O, omegaVec, $V([1, 1]), "TEX:$\\vec{\\omega}$"); + } + + this.arrow(O, p, "position"); + this.labelLine(O, p, $V([1, 0]), "TEX:$\\hat{a}$"); + + if (this.getOption("showVelocity")) { + this.arrow(p, p.add(v), "velocity"); + this.labelLine(p, p.add(v), $V([1, 0]), "TEX:$\\dot{\\hat{a}}$"); + } + + this.circleArrow3D(O, 0.7, Vector.k, Vector.i, -omega / 2, omega / 2, "angVel"); + var omegaText = (omega >= 0) ? "TEX:$\\omega$" : "TEX:$-\\omega$"; + this.labelCircleLine3D(omegaText, $V([1, 1]), O, 0.7, Vector.k, Vector.i, -omega / 2, omega / 2); + + this.circleArrow3D(O, 0.5, Vector.k, Vector.i, 0, theta, "angle"); + var thetaText = (theta >= 0) ? "TEX:$\\theta$" : "TEX:$-\\theta$"; + this.labelCircleLine3D(thetaText, $V([0, -1]), O, 0.5, Vector.k, Vector.i, 0, theta); + }); + + rkr_fe_c.activate3DControl(); + + rkr_fg_c = new PrairieDrawAnim("rkr-fg-c", function(t) { + this.setUnits(9, 6); + + this.addOption("showLabels", true); + this.addOption("showMoving", true); + this.addOption("showRigid", false); + this.addOption("showFixed", false); + this.addOption("showDerivatives", false); + + var O = $V([0, 0]); + var theta = t - 1.5 * Math.cos(t) + Math.PI / 2; + var omega = 1 + 1.5 * Math.sin(t); + + var bases = [ + $V([-0.7, -0.7]).rotate(theta, O), + $V([0.7, 0.2]).rotate(theta, O), + $V([-0.3, 0.5]).rotate(theta, O), + $V([0.4, -0.9]).rotate(theta, O), + ]; + + var moveBases = [ + $V([0.4 * Math.sin(0.4 * t), Math.sin(0.9 * t + 0.5)]), + $V([0.4 * Math.cos(0.6 * t), Math.sin(1.5 * t)]), + $V([0.4 * Math.sin(0.7 * t + 3), Math.cos(1.3 * t + 3)]), + $V([0.4 * Math.sin(1.2 * t + 0.8), Math.cos(0.2 * t + 1.2)]), + ]; + + var vecs = [ + $V([0.7, 0.7]).rotate(theta, O), + $V([0.2, -0.5]).rotate(theta, O), + $V([-0.6, 0.8]).rotate(theta, O), + $V([-0.5, -0.4]).rotate(theta, O), + ]; + + var derivatives = [ + vecs[0].rotate(Math.PI / 2, O).x(omega), + vecs[1].rotate(Math.PI / 2, O).x(omega), + vecs[2].rotate(Math.PI / 2, O).x(omega), + vecs[3].rotate(Math.PI / 2, O).x(omega), + ]; + + var offset = $V([0.3 * Math.sin(0.8 * t), Math.sin(2 * 0.8 * t)]); + + var omegaText = (omega >= 0) ? "TEX:$\\omega$" : "TEX:$-\\omega$"; + + if (this.getOption("showMoving")) { + this.save(); + this.translate($V([-3, 0])); + this.arrow(moveBases[0], moveBases[0].add(vecs[0]), "position"); + this.arrow(moveBases[1], moveBases[1].add(vecs[1]), "acceleration"); + this.arrow(moveBases[2], moveBases[2].add(vecs[2]), "angMom"); + this.arrow(moveBases[3], moveBases[3].add(vecs[3])); + /*if (this.getOption("showLabels")) { + this.labelLine(moveBases[0], moveBases[0].add(vecs[0]), $V([1, 0]), "TEX:$\\vec{a}$"); + this.labelLine(moveBases[1], moveBases[1].add(vecs[1]), $V([1, 0]), "TEX:$\\vec{b}$"); + this.labelLine(moveBases[2], moveBases[2].add(vecs[2]), $V([1, 0]), "TEX:$\\vec{c}$"); + this.labelLine(moveBases[3], moveBases[3].add(vecs[3]), $V([1, 0]), "TEX:$\\vec{d}$"); + }*/ + if (this.getOption("showDerivatives")) { + this.arrow(moveBases[0].add(vecs[0]), moveBases[0].add(vecs[0]).add(derivatives[0]), "velocity"); + this.arrow(moveBases[1].add(vecs[1]), moveBases[1].add(vecs[1]).add(derivatives[1]), "velocity"); + this.arrow(moveBases[2].add(vecs[2]), moveBases[2].add(vecs[2]).add(derivatives[2]), "velocity"); + this.arrow(moveBases[3].add(vecs[3]), moveBases[3].add(vecs[3]).add(derivatives[3]), "velocity"); + } + this.circleArrow(O, 1, Math.PI / 2 - omega / 2, Math.PI / 2 + omega / 2, "angVel", true, 0.1); + this.labelCircleLine(O, 1, Math.PI / 2 - omega / 2, Math.PI / 2 + omega / 2, $V([0, 1]), omegaText, true); + this.restore(); + } + + if (this.getOption("showRigid")) { + this.save(); + this.translate($V([0, 0])); + this.translate(offset); + this.arrow(bases[0], bases[0].add(vecs[0]), "position"); + this.arrow(bases[1], bases[1].add(vecs[1]), "acceleration"); + this.arrow(bases[2], bases[2].add(vecs[2]), "angMom"); + this.arrow(bases[3], bases[3].add(vecs[3])); + /*if (this.getOption("showLabels")) { + this.labelLine(bases[0], bases[0].add(vecs[0]), $V([1, 0]), "TEX:$\\vec{a}$"); + this.labelLine(bases[1], bases[1].add(vecs[1]), $V([1, 0]), "TEX:$\\vec{b}$"); + this.labelLine(bases[2], bases[2].add(vecs[2]), $V([1, 0]), "TEX:$\\vec{c}$"); + this.labelLine(bases[3], bases[3].add(vecs[3]), $V([1, 0]), "TEX:$\\vec{d}$"); + }*/ + if (this.getOption("showDerivatives")) { + this.arrow(bases[0].add(vecs[0]), bases[0].add(vecs[0]).add(derivatives[0]), "velocity"); + this.arrow(bases[1].add(vecs[1]), bases[1].add(vecs[1]).add(derivatives[1]), "velocity"); + this.arrow(bases[2].add(vecs[2]), bases[2].add(vecs[2]).add(derivatives[2]), "velocity"); + this.arrow(bases[3].add(vecs[3]), bases[3].add(vecs[3]).add(derivatives[3]), "velocity"); + } + this.circleArrow(O, 1, theta + Math.PI / 2 - omega / 2, theta + Math.PI / 2 + omega / 2, "angVel", true, 0.1); + this.labelCircleLine(O, 1, theta + Math.PI / 2 - omega / 2, theta + Math.PI / 2 + omega / 2, $V([0, 1]), omegaText, true); + this.restore(); + } + + if (this.getOption("showFixed")) { + this.save(); + this.translate($V([3, 0])); + this.arrow(O, vecs[0], "position"); + this.arrow(O, vecs[1], "acceleration"); + this.arrow(O, vecs[2], "angMom"); + this.arrow(O, vecs[3]); + /*if (this.getOption("showLabels")) { + this.labelLine(O, vecs[0], $V([1, 0]), "TEX:$\\vec{a}$"); + this.labelLine(O, vecs[1], $V([1, 0]), "TEX:$\\vec{b}$"); + this.labelLine(O, vecs[2], $V([1, 0]), "TEX:$\\vec{c}$"); + this.labelLine(O, vecs[3], $V([1, 0]), "TEX:$\\vec{d}$"); + }*/ + if (this.getOption("showDerivatives")) { + this.arrow(vecs[0], vecs[0].add(derivatives[0]), "velocity"); + this.arrow(vecs[1], vecs[1].add(derivatives[1]), "velocity"); + this.arrow(vecs[2], vecs[2].add(derivatives[2]), "velocity"); + this.arrow(vecs[3], vecs[3].add(derivatives[3]), "velocity"); + } + this.circleArrow(O, 1, Math.PI / 2 - omega / 2, Math.PI / 2 + omega / 2, "angVel", true, 0.1); + this.labelCircleLine(O, 1, Math.PI / 2 - omega / 2, Math.PI / 2 + omega / 2, $V([0, 1]), omegaText, true); + this.restore(); + } + }); + + rkt_fb_c = new PrairieDrawAnim("rkt-fb-c", function(t) { + this.setUnits(6.6, 4.4); + + this.addOption("showLabels", true); + this.addOption("showPosition", true); + this.addOption("showVelocity", false); + this.addOption("showAcceleration", false); + this.addOption("showAccDecomp", false); + this.addOption("showCenter", false); + this.addOption("showCircle", false); + this.addOption("showAngVel", false); + this.addOption("showAngVelDecomp", false); + + var label = this.getOption("showLabels") ? true : undefined; + + var O = $V([0, 0, 0]); + var rX = $V([1, 0, 0]); + var rY = $V([0, 1, 0]); + var rZ = $V([0, 0, 1]); + var gS = 2; // ground size + + var groundBorder = [$V([-gS, -gS, 0]), $V([-gS, gS, 0]), $V([gS, gS, 0]), $V([gS, -gS, 0])]; + var nGrid = 3; + for (var i = -nGrid; i <= nGrid; i++) { + this.line($V([i / nGrid * gS, -gS, 0]), $V([i / nGrid * gS, gS, 0]), "grid"); + this.line($V([-gS, i / nGrid * gS, 0]), $V([gS, i / nGrid * gS, 0]), "grid"); + } + this.polyLine(groundBorder, true, false); + this.arrow(O, rX); + this.arrow(O, rY); + this.arrow(O, rZ); + if (this.getOption("showLabels")) { + this.labelLine(O, rX, $V([1, -1]), "TEX:$x$"); + this.labelLine(O, rY, $V([1, 1]), "TEX:$y$"); + this.labelLine(O, rZ, $V([1, 1]), "TEX:$z$"); + } + + var f = function(t) { + return { + P: $V([1.8 * Math.cos(t / 2), 1.8 * Math.sin(t / 2), 1 - 0.9 * Math.cos(t)]) + }; + } + + var basis = function(t) { + var val = this.numDiff(f, t); + + var b = {}; + b.r = val.P; + b.v = val.diff.P; + b.a = val.ddiff.P; + + b.et = b.v.toUnitVector(); + b.en = this.orthComp(b.a, b.v).toUnitVector(); + b.eb = b.et.cross(b.en); + return b; + }.bind(this); + + var b = this.numDiff(basis, t); + var r = b.r; + var v = b.v; + var a = b.a; + var et = b.et; + var en = b.en; + var eb = b.eb; + + var at = this.orthProj(a, et); + var an = this.orthProj(a, en); + + var rho = Math.pow(v.modulus(), 2) / an.modulus(); + var kappa = 1 / rho; + var C = r.add(en.x(rho)); + + var ebDot = b.diff.eb; + var tau = -ebDot.dot(en) / v.modulus(); + var omega = et.x(tau * v.modulus()).add(eb.x(kappa * v.modulus())); + var omegat = this.orthProj(omega, et); + var omegab = this.orthProj(omega, eb); + + var path = []; + var nPoints = 100; + for (var i = 0; i < nPoints; i++) { + var tTemp = i / nPoints * 4 * Math.PI; + path.push(f(tTemp).P); + } + this.polyLine(path, true, false); + + this.point(r); + this.arrow(r, r.add(et)); + this.arrow(r, r.add(en)); + this.arrow(r, r.add(eb)); + this.labelLine(r, r.add(et), $V([1, 0]), label && "TEX:$\\hat{e}_t$"); + this.labelLine(r, r.add(en), $V([1, 0]), label && "TEX:$\\hat{e}_n$"); + this.labelLine(r, r.add(eb), $V([1, 0]), label && "TEX:$\\hat{e}_b$"); + if (this.getOption("showCircle")) { + this.save(); + this.setProp("shapeOutlineColor", this.getProp("rotationColor")); + this.arc3D(C, rho, eb); + this.restore(); + } + if (this.getOption("showCenter")) { + this.save(); + this.setProp("shapeOutlineColor", this.getProp("rotationColor")); + this.line(C, r); + this.labelLine(C, r, $V([0, 1]), label && "TEX:$\\rho$"); + this.point(C); + this.labelIntersection(C, [r], label && "TEX:$C$"); + this.restore(); + } + + if (this.getOption("showPosition")) { + this.arrow(O, r, "position"); + this.labelLine(O, r, $V([0, 1]), label && "TEX:$\\vec{r}$"); + } + if (this.getOption("showVelocity")) { + this.arrow(r, r.add(v), "velocity"); + this.labelLine(r, r.add(v), $V([0, 1]), label && "TEX:$\\vec{v}$"); + } + if (this.getOption("showAcceleration")) { + this.arrow(r, r.add(a), "acceleration"); + this.labelLine(r, r.add(a), $V([0, 1]), label && "TEX:$\\vec{a}$"); + } + if (this.getOption("showAccDecomp")) { + this.arrow(r, r.add(at), "acceleration"); + this.arrow(r, r.add(an), "acceleration"); + this.labelLine(r, r.add(at), $V([0, 1]), label && "TEX:$\\vec{a}_t$"); + this.labelLine(r, r.add(an), $V([0, 1]), label && "TEX:$\\vec{a}_n$"); + } + if (this.getOption("showAngVel")) { + this.arrow(r, r.add(omega), "angVel"); + this.labelLine(r, r.add(omega), $V([0, 1]), label && "TEX:$\\vec\\omega$"); + } + if (this.getOption("showAngVelDecomp")) { + this.arrow(r, r.add(omegat), "angVel"); + this.arrow(r, r.add(omegab), "angVel"); + this.labelLine(r, r.add(omegat), $V([0, 1]), label && "TEX:$\\vec\\omega_t$"); + this.labelLine(r, r.add(omegab), $V([0, 1]), label && "TEX:$\\vec\\omega_b$"); + } + }); + + rkt_fb_c.activate3DControl(); + + rkt_ft_c = new PrairieDrawAnim("rkt-ft-c", function(t) { + this.setUnits(12, 8); + + this.addOption("movement", "circle"); + this.addOption("showLabels", true); + this.addOption("showPath", false); + this.addOption("showCenter", false); + this.addOption("showCircle", false); + this.addOption("showPosition", true); + this.addOption("showVelocity", false); + this.addOption("showAcceleration", false); + this.addOption("showAccDecomp", false); + this.addOption("showAngVel", false); + this.addOption("origin", "O1"); + + var f; + if (this.getOption("movement") === "arc") { + f = function(t) { + t = -t; + t += 5; + return { + "period": 2 * Math.PI / 0.5, + "P": this.polarToRect($V([2 - 0.5 * Math.cos(0.5 * t) - 0.5 * Math.cos(t), Math.PI / 2 + 2.5 * Math.sin(0.5 * t)])) + }; + }; + } else if (this.getOption("movement") === "circle") { + f = function(t) { + return { + "period": 2 * Math.PI / 0.5, + "P": this.polarToRect($V([2.5, 0.5 * t])) + }; + }; + } else if (this.getOption("movement") === "varCircle") { + f = function(t) { + return { + "period": 2 * Math.PI / 0.5, + "P": this.polarToRect($V([2.5, -0.5 * t + 0.2 * Math.sin(t)])) + }; + }; + } else if (this.getOption("movement") === "ellipse") { + f = function(t) { + t += 3; + return { + "period": 2 * Math.PI / 0.7, + "P": $V([Math.cos(0.7 * t), 3 * Math.sin(0.7 * t)]) + }; + }; + } else if (this.getOption("movement") === "trefoil") { + f = function(t) { + t += 4; + return { + "period": 2 * Math.PI / 0.4, + "P": $V([Math.cos(0.4 * t) - 2 * Math.cos(2 * 0.4 * t), Math.sin(0.4 * t) + 2 * Math.sin(2 * 0.4 * t)]) + }; + }; + } else if (this.getOption("movement") === "eight") { + f = function(t) { + t += 2.5 * Math.PI; + return { + "period": 2 * Math.PI / 0.5, + "P": this.polarToRect($V([3 * Math.cos(0.5 * t), Math.sin(0.5 * t)])) + }; + }; + } else if (this.getOption("movement") === "comet") { + f = function(t) { + t += 1; + var T = 2 * Math.PI / 0.7; // period + var a = 2; // semi-major axis + var e = 0.5; // eccentricity + var b = a * Math.sqrt(1 - e*e); // semi-minor axis + var M = 2 * Math.PI * t / T; // mean anomaly + var E = M; // eccentric anomaly + // solve M = E - e * sin(E) for E with Newton's method + for (var i = 0; i < 5; i++) { + E = E + (M - (E - e * Math.sin(E))) / (1 - e * Math.cos(E)); + } + return { + "period": T, + "P": $V([a * (Math.cos(E) - e), b * Math.sin(E)]) + };}; + } else if (this.getOption("movement") === "pendulum") { + f = function(t) { + t -= 1.5; + return { + "period": 2 * Math.PI / 0.6, + "P": this.polarToRect($V([2.5, -Math.PI / 2 + Math.cos(0.6 * t)])) + }; + }; + } + f = f.bind(this); + + var O1 = $V([0, 0]); + var O2 = $V([-3, -2]); + + var O; + if (this.getOption("origin") === "O1") { + O = O1; + } else { + O = O2; + } + + var val = this.numDiff(f, t); + var period = val.period; + var r = val.P; + var v = val.diff.P; + var a = val.ddiff.P; + + var ei = $V([1, 0]); + var ej = $V([0, 1]); + + var et = v.toUnitVector(); + var en = this.orthComp(a, v).toUnitVector(); + + var vt = this.orthProj(v, et); + var vn = this.orthProj(v, en); + var at = this.orthProj(a, et); + var an = this.orthProj(a, en); + + var label = this.getOption("showLabels") ? true : undefined; + + var rho = Math.pow(v.modulus(), 2) / an.modulus(); + var C = r.add(en.x(rho)); + + var kappa = 1 / rho; + var omega = v.modulus() * kappa; + + if (this.getOption("showPath")) { + var n = 200; + var path = [], s; + for (var i = 0; i < n; i++) { + s = i / n * period; + path.push(f(s).P); + } + this.polyLine(path, true, false); + } + this.point(O1); + this.text(O1, $V([1, 1]), label && "TEX:$O_1$"); + this.point(O2); + this.text(O2, $V([1, 1]), label && "TEX:$O_2$"); + this.point(r); + this.labelIntersection(r, [O, r.add(et), r.add(en)], label && "TEX:$P$"); + if (this.getOption("showCircle")) { + this.save(); + this.setProp("shapeOutlineColor", this.getProp("rotationColor")); + this.arc(C, rho); + this.restore(); + } + if (this.getOption("showCenter")) { + this.save(); + this.setProp("shapeOutlineColor", this.getProp("rotationColor")); + this.line(C, r); + this.labelLine(C, r, $V([0, 1]), label && "TEX:$\\rho$"); + this.point(C); + this.labelIntersection(C, [r], label && "TEX:$C$"); + this.restore(); + } + if (this.getOption("showPosition")) { + this.arrow(O, r, "position"); + this.labelLine(O, r, $V([0, 1]), label && "TEX:$\\vec{r}$"); + } + this.arrow(r, r.add(et)); + this.arrow(r, r.add(en)); + this.labelLine(r, r.add(et), $V([1, 1]), label && "TEX:$\\hat{e}_t$"); + this.labelLine(r, r.add(en), $V([1, 1]), label && "TEX:$\\hat{e}_n$"); + if (this.getOption("showVelocity")) { + this.arrow(r, r.add(v), "velocity"); + this.labelLine(r, r.add(v), $V([0, -1]), label && "TEX:$\\vec{v}$"); + } + if (this.getOption("showAcceleration")) { + this.arrow(r, r.add(a), "acceleration"); + this.labelLine(r, r.add(a), $V([1, 0]), label && "TEX:$\\vec{a}$"); + } + if (this.getOption("showAccDecomp") && at.modulus() > 1e-3) { + this.arrow(r, r.add(at), "acceleration"); + this.labelLine(r, r.add(at), $V([1, 1]), label && "TEX:$\\vec{a}_t$"); + } + if (this.getOption("showAccDecomp") && an.modulus() > 1e-3) { + this.arrow(r, r.add(an), "acceleration"); + this.labelLine(r, r.add(an), $V([1, 1]), label && "TEX:$\\vec{a}_n$"); + } + if (this.getOption("showAngVel") && Math.abs(omega) > 1e-3) { + var ebSign = et.to3D().cross(en.to3D()).dot(Vector.k); + var avOffset = (this.getOption("showPath") || this.getOption("showCircle")) ? Math.PI / 2 : 3 * Math.PI / 4; + var a0 = this.angleOf(et) - ebSign * omega - ebSign * avOffset; + var a1 = this.angleOf(et) + ebSign * omega - ebSign * avOffset; + var omegaLabel = (ebSign > 0) ? "TEX:$\\omega$" : "TEX:$-\\omega$"; + this.circleArrow(r, 0.6, a0, a1, "angVel"); + this.labelCircleLine(r, 0.6, a0, a1, $V([0, 1]), label && omegaLabel); + } + }); + + rkt_ft_c.registerOptionCallback("movement", function (value) { + rkt_ft_c.resetTime(false); + rkt_ft_c.resetOptionValue("showPath"); + rkt_ft_c.resetOptionValue("showVelocity"); + rkt_ft_c.resetOptionValue("showAcceleration"); + rkt_ft_c.resetOptionValue("showAccDecomp"); + rkt_ft_c.resetOptionValue("showCenter"); + rkt_ft_c.resetOptionValue("showCircle"); + }); + + rkt_ft_c.registerOptionCallback("origin", function (value) { + rkt_ft_c.setOption("showPosition", true); + }); + + $( window ).on( "resize", function() { + rkt_fb_c.redraw(); + rkr_fg_c.redraw(); + rkr_fe_c.redraw(); + rkr_fc_c.redraw(); + rkt_ft_c.redraw(); + } ); + +}); // end of document.ready() diff --git a/public/dyn/vector_calculus/canvases.js b/public/dyn/vector_calculus/canvases.js index 7fff9d1c3..b00853023 100644 --- a/public/dyn/vector_calculus/canvases.js +++ b/public/dyn/vector_calculus/canvases.js @@ -518,4 +518,179 @@ $(document).ready(function(){ rvc_fp_c.resetOptionValue("showVelocity"); rvc_fp_c.resetOptionValue("showFixedBase"); }); + + rvc_fc_c = new PrairieDraw("rvc-fc-c", function() { + this.setUnits(12, 8); + + this.addOption("t", 0); + this.addOption("showLabels", true); + this.addOption("showComponent1", false); + this.addOption("showComponent2", false); + this.addOption("showVelocity", false); + this.addOption("basis", "ij"); + + var v_f = function(t) { + return $V([5 * Math.sin(Math.PI * t / 10), 1.5 * Math.cos(Math.PI * 3 * t / 10)]); + }; + var dv_f = function(t) { + return $V([5 * Math.PI / 10 * Math.cos(Math.PI * t / 10), - 4.5 / 10 * Math.PI * Math.sin(Math.PI * 3 * t / 10)]); + }; + + var t = this.getOption("t"); + + var O = $V([0, 0]); + if (this.getOption("basis") === "ij") { + var e1 = $V([1, 0]); + var e2 = $V([0, 1]); + } else { + var e1 = $V([1, 0]).rotate(Math.PI / 6, O); + var e2 = $V([0, 1]).rotate(Math.PI / 6, O); + } + + var v = v_f(t); + var dv = dv_f(t); + + // add fuzzing to avoid exact zeros + var v1c = e1.dot(v) + 1e-6 + var v2c = e2.dot(v) + 1e-6 + var v1 = e1.x(v1c); + var v2 = e2.x(v2c); + var dv1c = e1.dot(dv) + 1e-6; + var dv2c = e2.dot(dv) + 1e-6; + var dv1 = e1.x(dv1c); + var dv2 = e2.x(dv2c); + + var t_max = 10; + + var i, s; + var path = [], path_v1 = [], path_v2 = [], path_dv1 = [], path_dv2 = []; + var n = Math.round(t_max / 0.1); + for (i = 0; i <= n; i++) { + s = i / n * t_max; + var v_s = v_f(s); + var dv_s = dv_f(s); + path.push(v_s); + path_v1.push($V([s, e1.dot(v_s)])); + path_v2.push($V([s, e2.dot(v_s)])); + path_dv1.push($V([s, e1.dot(dv_s)])); + path_dv2.push($V([s, e2.dot(dv_s)])); + } + + var labelA = "TEX:$\\vec{a}$"; + var labelDotA = "TEX:$\\dot{\\vec{a}}$"; + var labelE1, labelE2, labelA1c, labelA2c, labelDotA1c, labelDotA2c, labelA1, labelA2, labelDotA1, labelDotA2; + if (this.getOption("basis") === "ij") { + labelE1 = "TEX:$\\hat\\imath$"; + labelE2 = "TEX:$\\hat\\jmath$"; + labelA1c = "TEX:$a_i$"; + labelA2c = "TEX:$a_j$"; + labelDotA1c = "TEX:$\\dot{a}_i$"; + labelDotA2c = "TEX:$\\dot{a}_j$"; + labelA1 = "TEX:$a_i\\hat\\imath$"; + labelA2 = "TEX:$a_j\\hat\\jmath$"; + labelDotA1 = "TEX:$\\dot{a}_i\\hat\\imath$"; + labelDotA2 = "TEX:$\\dot{a}_j\\hat\\jmath$"; + } else { + labelE1 = "TEX:$\\hat{u}$"; + labelE2 = "TEX:$\\hat{v}$"; + labelA1c = "TEX:$a_u$"; + labelA2c = "TEX:$a_v$"; + labelDotA1c = "TEX:$\\dot{a}_u$"; + labelDotA2c = "TEX:$\\dot{a}_v$"; + labelA1 = "TEX:$a_u\\hat{u}$"; + labelA2 = "TEX:$a_v\\hat{v}$"; + labelDotA1 = "TEX:$\\dot{a}_u\\hat{u}$"; + labelDotA2 = "TEX:$\\dot{a}_v\\hat{v}$"; + } + if (!this.getOption("showLabels")) { + labelA = undefined; + labelDotA = undefined; + labelA1 = undefined; + labelA2 = undefined; + labelDotA1 = undefined; + labelDotA2 = undefined; + } + + var axSizeDw = $V([5, 3]); + var axPOriginData = $V([0, -4]); + var axPSizeData = $V([t_max * 1.1, 10]); + var axVOriginData = $V([0, -2]); + var axVSizeData = $V([t_max * 1.1, 5]); + + this.save(); + this.translate($V([-5.3, -3.5])); + if (this.getOption("showComponent1")) { + this.plot(path_v1, O, axSizeDw, axPOriginData, axPSizeData, "TEX:$t$", undefined, "position", true, false, undefined, undefined, {"horizAxisPos": 0}); + this.plot([$V([t, v1c])], O, axSizeDw, axPOriginData, axPSizeData, "TEX:$t$", undefined, "position", false, true, labelA1c, $V([1, 1])); + if (this.getOption("showVelocity")) { + this.plot(path_dv1, O, axSizeDw, axVOriginData, axVSizeData, undefined, undefined, "velocity", false, false); + this.plot([$V([t, dv1c])], O, axSizeDw, axVOriginData, axVSizeData, undefined, undefined, "velocity", false, true, labelDotA1c, $V([-1, -1])); + } + } else { + this.plot([], O, axSizeDw, axPOriginData, axPSizeData, "TEX:$t$", undefined, "position", true, false, undefined, undefined, {"horizAxisPos": 0}); + } + this.restore(); + + this.save(); + this.translate($V([0.5, -3.5])); + if (this.getOption("showComponent2")) { + this.plot(path_v2, O, axSizeDw, axPOriginData, axPSizeData, "TEX:$t$", undefined, "position", true, false, undefined, undefined, {"horizAxisPos": 0}); + this.plot([$V([t, v2c])], O, axSizeDw, axPOriginData, axPSizeData, "TEX:$t$", undefined, "position", false, true, labelA2c, $V([-1, -1])); + if (this.getOption("showVelocity")) { + this.plot(path_dv2, O, axSizeDw, axVOriginData, axVSizeData, undefined, undefined, "velocity", false, false); + this.plot([$V([t, dv2c])], O, axSizeDw, axVOriginData, axVSizeData, undefined, undefined, "velocity", false, true, labelDotA2c, $V([1, 1])); + } + } else { + this.plot([], O, axSizeDw, axPOriginData, axPSizeData, "TEX:$t$", undefined, "position", true, false, undefined, undefined, {"horizAxisPos": 0}); + } + this.restore(); + + var v_offset = 0.1; + + this.save(); + this.translate($V([-1.5, 1.5])); + this.polyLine(path); + this.arrow(O, v, "position"); + this.labelLine(O, v, $V([-1, 0]), labelA); + if (this.getOption("showComponent1")) { + this.arrow(v2, v, "position"); + this.labelLine(v2, v, $V([0, 1]), labelA1); + } + if (this.getOption("showComponent2")) { + this.arrow(v1, v, "position"); + this.labelLine(v1, v, $V([0, 1]), labelA2); + } + if (this.getOption("showVelocity")) { + this.arrow(v, v.add(dv), "velocity"); + this.labelLine(v, v.add(dv), $V([1, 0]), labelDotA); + if (this.getOption("showComponent1")) { + this.arrow(v, v.add(dv1), "velocity"); + this.labelLine(v, v.add(dv1), $V([0, 1]), labelDotA1); + } + if (this.getOption("showComponent2")) { + this.arrow(v, v.add(dv2), "velocity"); + this.labelLine(v, v.add(dv2), $V([0, 1]), labelDotA2); + } + } + this.restore(); + + this.save(); + this.translate($V([-4.5, 1.5])); + this.arrow(O, e1); + this.arrow(O, e2); + this.labelLine(O, e1, $V([1, -1]), labelE1); + this.labelLine(O, e2, $V([1, 1]), labelE2); + this.restore(); + }); + + $( window ).on( "resize", function() { + rvv_ed_c.redraw(); + rvv_fn_c.redraw(); + rvv_eo_c.redraw(); + rvv_fx_c.redraw(); + rvc_fi_c.redraw(); + rvc_fd_c.redraw(); + rvc_fp_c.redraw(); + rvc_fc_c.redraw(); + } ); }) \ No newline at end of file diff --git a/public/dyn/vectors/canvases.js b/public/dyn/vectors/canvases.js index f37492454..0e642f914 100644 --- a/public/dyn/vectors/canvases.js +++ b/public/dyn/vectors/canvases.js @@ -38,7 +38,7 @@ $(document).ready(function(){ this.text(T, $V([0, -1]), msg); }); - var rvp_fc_c = new PrairieDraw("rvp-fc-c", function() { + rvp_fc_c = new PrairieDraw("rvp-fc-c", function() { this.setUnits(8, 8); var d = 3; @@ -192,56 +192,6 @@ $(document).ready(function(){ }); - rvv_fu_c = new PrairieDraw("rvv-fu-c", function() { - this.setUnits(8, 4); - - var O = $V([0, 0]); - - var a = $V([0.6, -1]); - var b = $V([1.5, 1.5]); - var c = $V([-0.5, 0.4]); - - var aHat = a.toUnitVector(); - var bHat = b.toUnitVector(); - var cHat = c.toUnitVector(); - - this.save(); - this.translate($V([-3, 0])); - this.arrow(O, a, "red"); - this.arrow(O, b, "blue"); - this.arrow(O, c, "darkgreen"); - this.labelLine(O, a, $V([1, -1]), "TEX:$\\vec{a}$"); - this.labelLine(O, b, $V([1, -1]), "TEX:$\\vec{b}$"); - this.labelLine(O, c, $V([1, 1]), "TEX:$\\vec{c}$"); - this.restore(); - - this.save(); - this.translate($V([-0.2, -0.7])); - var d = 0.4; - this.line(O, $V([0, a.modulus()]), "red"); - this.text($V([0, -0.4]), $V([0, -1]), "TEX:$a$"); - this.translate($V([d, 0])); - this.line(O, $V([0, b.modulus()]), "blue"); - this.text($V([0, -0.4]), $V([0, -1]), "TEX:$b$"); - this.translate($V([d, 0])); - this.line(O, $V([0, c.modulus()]), "darkgreen"); - this.text($V([0, -0.4]), $V([0, -1]), "TEX:$c$"); - this.restore(); - - this.save(); - this.translate($V([2.5, 0])); - this.arrow(O, aHat, "red"); - this.arrow(O, bHat, "blue"); - this.arrow(O, cHat, "darkgreen"); - this.labelLine(O, aHat, $V([1, -1]), "TEX:$\\hat{a}$"); - this.labelLine(O, bHat, $V([1, -1]), "TEX:$\\hat{b}$"); - this.labelLine(O, cHat, $V([1, -1]), "TEX:$\\hat{c}$"); - this.restore(); - - this.text($V([0.3, -2]), $V([0, -1]), "TEX:vectors\\qquad$=$\\qquad lengths\\qquad$\\times$\\qquad directions"); - - }); - rvv_fb_c = new PrairieDraw("rvv-fb-c", function() { this.setUnits(6, 4); @@ -269,34 +219,6 @@ $(document).ready(function(){ this.labelLine(ei.x(a.e(1)), a, $V([0, -1]), "TEX:$2\\hat\\jmath$"); }); - - rvv_fb_c = new PrairieDraw("rvv-fb-c", function() { - this.setUnits(6, 4); - - var O = $V([0, 0]); - var a = $V([3, 2]); - var ei = $V([1, 0]); - var ej = $V([0, 1]); - - this.translate($V([-2.3, -1.3])); - - this.arrow(O, ei); - this.arrow(O, ej); - this.labelLine(O, ei, $V([1, -1]), "TEX:$\\hat\\imath$"); - this.labelLine(O, ej, $V([1, 1]), "TEX:$\\hat\\jmath$"); - - this.translate($V([1.3, 0.5])); - - this.arrow(O, a, "red"); - this.labelLine(O, a, $V([0, -1]), "TEX:$\\vec{a}$"); - - this.arrow(O, ei.x(a.e(1))); - this.labelLine(O, ei.x(a.e(1)), $V([0, -1]), "TEX:$3\\hat\\imath$"); - - this.arrow(ei.x(a.e(1)), a); - this.labelLine(ei.x(a.e(1)), a, $V([0, -1]), "TEX:$2\\hat\\jmath$"); - - }); rvv_f3_c = new PrairieDraw("rvv-f3-c", function() { this.setUnits(6, 3); @@ -1611,4 +1533,30 @@ $(document).ready(function(){ } this.restore(); }); + + $( window ).on( "resize", function() { + rvv_fc_c.redraw(); + rvp_fc_c.redraw(); + rvp_fp_c.redraw(); + rvv_fu_c.redraw(); + rvv_fb_c.redraw(); + rvv_f3_c.redraw(); + rvv_fy_c.redraw(); + rvv_fr_c.redraw(); + rvv_fl_c.redraw(); + rvv_ft_c.redraw(); + rvv_xn_c.redraw(); + rvv_e2_c.redraw(); + rvv_xa_c.redraw(); + rvv_xx_c.redraw(); + rvv_fm_c.redraw(); + rvc_fm_c.redraw(); + rvs_fd_c.redraw(); + rvs_ec_c.redraw(); + aos_fm_c.redraw(); + aos_fd_c.redraw(); + aos_fp_c.redraw(); + rvc_fm_c.redraw(); + rvs_fd_c.redraw(); + } ); }) \ No newline at end of file diff --git a/src/components/CalloutCard.astro b/src/components/CalloutCard.astro index 282e68550..8acf2171b 100644 --- a/src/components/CalloutCard.astro +++ b/src/components/CalloutCard.astro @@ -3,6 +3,10 @@ const {title='Did you know?'} = Astro.props; ---
-

{title}

- +
+

{title}

+
+
+ +
\ No newline at end of file diff --git a/src/components/CalloutContainer.astro b/src/components/CalloutContainer.astro index 399f928f9..84d3c6ea3 100644 --- a/src/components/CalloutContainer.astro +++ b/src/components/CalloutContainer.astro @@ -1,6 +1,6 @@
-
+
diff --git a/src/components/DisplayEquation.astro b/src/components/DisplayEquation.astro index 11b9d96f6..992cec30f 100644 --- a/src/components/DisplayEquation.astro +++ b/src/components/DisplayEquation.astro @@ -15,6 +15,8 @@ const { equation, id="", title="", derivation="", background=""} = Astro.props; border: 1px solid #444; border-radius: 5px; } + + @@ -24,8 +26,10 @@ const { equation, id="", title="", derivation="", background=""} = Astro.props; {title && title}{id && {` #${id}`}}
- {`$$ ${equation} $$`} - +
+ {`$$ ${equation} $$`} +
+ {derivation && } {derivation &&
diff --git a/src/components/Image.astro b/src/components/Image.astro index 9756d612d..5cb4209db 100644 --- a/src/components/Image.astro +++ b/src/components/Image.astro @@ -6,7 +6,7 @@ const img_path_split = src.split('/') const filename = 'Fig: ' + img_path_split.pop().replace('.png', '') --- - -
-
+
+
{alt}
{filename}
diff --git a/src/components/PrairieDrawCanvas.astro b/src/components/PrairieDrawCanvas.astro index 36721213f..371d39161 100644 --- a/src/components/PrairieDrawCanvas.astro +++ b/src/components/PrairieDrawCanvas.astro @@ -9,13 +9,43 @@ import Center from "./Center.astro"; border: solid 1px; border-color: black; } + + .figureCaption{ + margin-top: 1rem; + } -
- -
-
- -
+ + +
+
+
+ + +
+ +
+
+ + diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro index b72edaa8b..122217ef3 100644 --- a/src/layouts/Layout.astro +++ b/src/layouts/Layout.astro @@ -6,7 +6,7 @@ const { title } = Astro.props; --- - + @@ -33,7 +33,7 @@ const { title } = Astro.props; - +
@@ -61,6 +61,10 @@ const { title } = Astro.props; } + mjx-container{ + max-width: 90vw; + } + body { font-size: 1.1rem; } diff --git a/src/pages/dyn/particle_kinematics.astro b/src/pages/dyn/particle_kinematics.astro index 43cea27e4..915a9915a 100644 --- a/src/pages/dyn/particle_kinematics.astro +++ b/src/pages/dyn/particle_kinematics.astro @@ -6,6 +6,13 @@ import SubSection from "../../components/SubSection.astro" import SubSubSection from "../../components/SubSubSection.astro" import BlueText from "../../components/BlueText.astro" import RedText from "../../components/RedText.astro" +import InlineEquation from "../../components/InlineEquation.astro" +import DisplayEquation from "../../components/DisplayEquation.astro" +import PrairieDrawCanvas from "../../components/PrairieDrawCanvas.astro" +import CalloutContainer from "../../components/CalloutContainer.astro" +import CalloutCard from "../../components/CalloutCard.astro" +import SubSubSubSection from "../../components/SubSubSubSection.astro" +import DisplayEquationCustom from "../../components/DisplayEquationCustom.astro" ---
@@ -22,43 +29,767 @@ import RedText from "../../components/RedText.astro"

Add the table summary shown in Fig \ref fig:PosVelAcce - + Complete in reference page "Position, velocity, and acceleration" + + - Angular velocity + + Complete in reference page "Rotations and angular velocity" + +

+ A rotation of a vector is a change which only + alters the direction, not the length, of a vector. A + rotation consists of a rotation axis and a + rotation rate. By taking the rotation axis as a + direction and the rotation rate as a length, we can write + the rotation as a vector, known as the angular velocity + vector . We use the + right-hand rule to describe the direction of + rotation. The units of are \(\rm rad/s\) or + . +

+ + +
+

+ + +

+

+ Rotation axis: + + + + + +

+

+ Angular velocity vector \(\vec\omega\). The direction of + \(\vec\omega\) is the axis of rotation, while the magnitude + is the speed of rotation (positive direction given by the + right-hand rule). +

+
+
+ + + +

+ The Greek letter ω (lowercase omega) is + the last letter of the Greek + alphabet, leading to expressions such as “from alpha + to omega” meaning “from start to end”. Omega literally + means O-mega, meaning O-large, as capital Omega (written + Ω) developed from capital Omicron + (written Ο) by breaking the circle and turning up the + edges. Omicron is literally O-micron, meaning O-small, and + it is the ancestor of the Latin + letter O that we use today in English. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ΑαalphaΙιiotaΡρrho
ΒβbetaΚκkappaΣσsigma
ΓγgammaΛλlambdaΤτtau
ΔδdeltaΜμmuΥυupsilon
ΕεepsilonΝνnuΦφphi
ΖζzetaΞξxiΧχchi
ΗηetaΟοomicronΨψpsi
ΘθthetaΠπpiΩωomega
+

+ The Greek alphabet, shown above, was the first true alphabet, + meaning that it has letters representing phonemes + (basic significant sounds) and includes vowels as + well as consonants. The + Greek alphabet was was derived from the earlier Phoenician + alphabet, which was probably the original parent of + all alphabets. This shows that the idea of an alphabet is + so non-obvious that it has only ever been invented once, + and then always copied after that. +

+
+
+ +
+ +

+ If a unit vector is rotating, then the angular + velocity vector is defined so that: +

+ + + + +

+ Using the same approach as #rvc-em we write and differentiate this and use rkr-ew to find: + + + + Comparing this to #rvc-em + shows that the two components are the projection and the + complementary projection, respectively. +

+
+ + +

+ This can be seen from the fact that if \(a\) + is constant (a fixed length vector), substituted into #rkr-ed. +

+
+ +
+ + +

+ In 2D the angular velocity can be thought of as a scalar + (positive for counter-clockwise, negative for clockwise). + This scalar is just the out-of-plane component of the + full angular velocity vector. We can draw the angular + velocity as either a vector pointing out of the plane, or + as a circle-arrow in the plane, which is simpler for 2D + diagrams. +

+ + +
+

+ + +

+

+ Show: + +

+

+ Comparison of the vector and scalar representations of + \(\vec\omega\) for 2D rotations. +

+
+
+ +

+ In 2D the angular velocity scalar \(\omega\) is simply the + derivative of the rotation angle \(\theta\) in the plane: +

+ + +

+ Take to be a unit vector rotating in the 2D + plane, making an angle of + \(\theta\) with the \(x\)-axis, as in Figure #rkr-f2. Then: + + + + Differentiating this expression gives: + + + + We now consider an angular velocity vector + \(\vec\omega\). Because the rotation is in the + \(\hat\imath\)–\(\hat\jmath\) plane, the angular velocity + vector must be in the direction. Thus + . Now we can compute the + derivative of using #rkr-ew, giving: + + + + Comparing this expression to the earlier one for + we see that \(\omega = \dot\theta\). +

+
+ +

+ The right-hand rule convention for angular velocities means + that counter-clockwise rotations are positive, just like the + usual angle direction convention. +

+ + + +

+ Angular directions have long been considered to have + magical or spiritual significance. In Britain the + counterclockwise direction was once known + as widdershins, + and it was considered unlucky to travel around a church in + a widdershins direction. +

+

+ Interestingly, right-handed people tend to naturally draw + circles in a counterclockwise direction, and clockwise + drawing in right-handed children is an early warning sign + for the later development of schizophrenia [Blau, 1977]. +

+
+

References

+
    +
  • + T. H. Blau. + Torque and schizophrenic vulnerability. + American Psychologist, 32(12):997–1005, 1977. + DOI: 10.1037/0003-066X.32.12.997. +
  • +
+
+
+
+
+ + +

+ The fact that vectors don't have + positions means that vector rotations are independent of + where vectors are drawn, just like for derivatives. +

+ + +
+ +

+ + +

+

+ Show: + + + +

+

+ Rotational motion of vectors which are drawn moving + about. Note that the drawn position does not affect the + angular velocity $\omega$ or the derivative vectors. +

+
+
+
+ + +

+ Rotations are rigid transformations, meaning that + they keep constant all vector lengths and all relative + vector angles. These facts are reflected in the following + results, which all consider two vectors and + that are rotating with angular velocity + . +

+ + +

+ Using #rkr-el and the scalar + triple product formula #rvi-es gives: + + +

+
+ + +

+ We first consider the dot product and show that this is not changing with + time. We do this by using the scalar triple product + formula #rvi-es to find: + + + + Now is constant and the lengths + \(a\) and \(b\) are constant, so the angle \(\theta\) between + the vectors must be constant. +

+
+ + +

+ From #rkr-el we know that the + derivative is + + + + but the cross product is zero for parallel vectors, so + this the derivative is zero. +

+
+
+ + +

+ Rodrigues’ rotation formula gives an explicit formula for a + vector rotated by an angle about a given axis. +

+ + +

+ Assume is not parallel to + . Then let and , so + is a right-handed orthonormal basis. Take + \(\phi\) to be the angle between and + . Then we do a rotation by \(\theta\) in + the plane: +

+

+ +

+

+ Now we want to convert from the + basis to write the rotated + result in terms of . To do this, we need to work + out what are in terms of + these other vectors. +

+

+ +

+

+ Substituting these into the rotated vector expression + above gives +

+

+ +

+
+
+ Complete in reference page "Position, velocity, and acceleration" This equation is displayed under the title "Velocity and acceleration in polar basis". Add the description of each term as shown in Fig \ref fig:AngularAccelerationEq - + Complete in reference page "Tangential/normal basis" + +

+ Consider a particle moving with position vector + and corresponding velocity and acceleration + . The tangential/normal basis + is: +

+ + +

+ These equations are definitions of the basis vectors, so + the only thing to derive is the alternative formula for + . Using the definition of above + and #rvc-eu, we see that + + + + Normalizing both sides gives the desired expression: + + +

+
+ +

+ The tangential basis vector points tangential to + the path, the normal basis vector points + perpendicular (normal) to the path towards the instantaneous + center of curvature, and the binormal basis vector + completes the right-handed basis. +

+ + +

+ + + +

+ + + + + + + + + +
Show: + + + + +
+ + + + +
+

+ Tangential/normal basis associated with movement around a + curve in 3D. Observe that the velocity is always + in the direction and that the acceleration + always lies in the plane + (the osculating plane). The center of curvature and + osculating circle are defined below. +

+
+ +

+ As the point \(P\) moves along its path, the associated + tangential/normal basis rotates with an angular velocity + vector \(\omega\) given by: +

+ + +

+ We start by writing the angular velocity in the + tangential/normal basis, giving: + + + + Now the basis vector derivatives are given by the cross + product by from #rkr-ew, so we can evaluate + the expressions #rkt-ek for + curvature and torsion to give: + + + + and + + + + Rearranging the final expressions in each case gives + and . + + From the definition #rkt-eb of + , we see that + + + + from which we conclude that , giving us + all three components of . +

+
+ +

+ Knowing the angular velocity vector of the tangential/normal + basis allows us to easily compute the time derivatives of + each tangential/normal basis vector, as follows: +

+ + +

+ We can use the expression #rkt-ew + for together with #rkr-ew to find the basis + vector derivatives: + + +

+
+ + + +

+ The tangential/normal basis is also called the + Frenet–Serret frame after Jean + Frédéric Frenet and Joseph + Alfred Serret, who discovered it independently around + 1850. The equations #rkt-ed for the + basis derivatives are often called the Frenet-Serret + formulas, typically written in terms of \(s\) derivatives: + + +

+

+ If we divide the angular velocity vector #rkt-ew by \(v\) then we obtain the + vector + + + + which is known as the Darboux + vector after its discoverer, Jean + Gaston Darboux. +

+
+
+ +
+ Complete in reference page "Tangential/normal basis" + +

+ While the motion of a point \(P\) along a path defines the + tangential/normal basis, we can also use this basis to + express the kinematics of \(P\) itself, giving the following + expressions for velocity and acceleration. +

+ + +

+ From the definition #rkt-eb of + we see that , which is the first equation + above. Differentiating this and using from + #rkt-es gives + + + + where we used the derivative #rkt-ed of in terms of + the curvature \(\kappa\), and the definition #rkt-ek of the radius of curvature to + give . +

+
+ +

+ The above formula shows that the normal acceleration + component \(a_n\) is determined by the radius of curvature. We + can therefore also find the radius of curvature from knowing + the normal acceleration: +

+ + +

+ From #rkt-ev we known that the + normal component of the acceleration is given by and from the definition #rkt-es of path length we have + , so this equation can be rearranged to + give . +

+

+ Now because only has and + components, the component is + given by + + + + where we used the facts that is in the + direction of , that + does not depend + on the magnitude of , and equation #rvv-em for the magnitude of + the complementary projection. +

+
+ + +

+ + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Movement: circle var-circle ellipse arc
trefoil eight comet pendulum
Show: + + + + +
+ + + + +
Origin: \(O_1\) \(O_2\)
+

+ Velocity and acceleration in the tangential/normal + basis. Note that the tangential/normal basis does not + depend on the choice of origin or the position vector, in + contrast to the polar basis. +

+
Complete in reference page "Tangential/normal basis" + + +

+ To better understand the geometry of the tangential/normal + basis, we can use the curvature \(\kappa\) to + describe the curving of the path, and the torsion + \(\tau\) to describe the rotation of the basis about the + path. These quantities are defined by: +

+ + +
+

+ These equations are definitions, so we need only check + that the two expressions for each of \(\kappa\) and \(\tau\) + are equivalent. This follows immediately, however, from + the chain-rule conversions #rkt-ea + between \(d/ds\) and \(d/dt\). +

+
+
+ +

+ The radius of curvature \(\rho\) is the radius of + equivalent circular motion, and the torsion + determines the rate of rotation of the osculating plane, as + described below in Section #rkt-so. +

+ +

+ Given a parametric curve, its curvature can be directly + evaluated with: +

+ + +

+ Because the tangential/normal basis vectors #rkt-eb are all normalized, it does + not matter how fast the point moves along the line. We + can thus evaluate the parametric curve as a function of + time, giving . Now: + + + + where we used the cross product length formula #rvv-el and equation #rkt-er for the radius of curvature + . By definition #rkt-ek the + curvature is , so + + +

+
+ +

+ While the above formula can be used in 2D by taking the + third component to be zero, it can also be written in an + explicitly 2D form: +

+ + +

+ This equation is just #rkt-ec + written in explicit 2D coordinates. To see this, we + first take the position vector to be + + + + Now and + + + + so evaluating #rkt-ec gives the + desired expression. +

+
+ +

+ We can take this a step further, and obtain an expression for an explicitly defined function. +

+ + +

+ Use equation #rkt‑e2 and parametrize the curve using \(x\) as the parametrization variable. Namely: + + + + This yields a very elegant expression, as and , which lets us arrive at the desired expression #rkt‑e3. +

+
Add summary table as in Fig \ref fig:SystemsComparison - + @@ -70,7 +801,7 @@ import RedText from "../../components/RedText.astro" This is mentioned in L07-Notes, Slide 6. This paper is cited https://doi.org/10.1016/j.egyr.2020.01.001. This picture is included \ref fig:AppFlywheel . Refers to "Angular accelerations". - + @@ -84,4 +815,6 @@ import RedText from "../../components/RedText.astro" This topic needs to be created, it was mentioned in lecture with no information or figure -
\ No newline at end of file + + + \ No newline at end of file diff --git a/src/pages/dyn/vector_calculus.astro b/src/pages/dyn/vector_calculus.astro index 678106f02..7e2f03c51 100644 --- a/src/pages/dyn/vector_calculus.astro +++ b/src/pages/dyn/vector_calculus.astro @@ -340,7 +340,7 @@ import Col from "../../components/Col.astro"

-
+

@@ -372,8 +372,8 @@ import Col from "../../components/Col.astro"

Time:

- - \(t = \) s + + \(t = \) 0 s
@@ -445,7 +445,7 @@ import Col from "../../components/Col.astro" Suppose we have another function \(g=g(s)\). Then

- s +

As you can see, while a superscribed dot always denotes @@ -490,7 +490,7 @@ import Col from "../../components/Col.astro"

-
+

@@ -512,6 +512,80 @@ import Col from "../../components/Col.astro" Taken from L03-Notes, slide 6. +

+ In a fixed basis we differentiate a vector by + differentiating each component: +

+ + +

+ Writing a time-dependent vector expression in a fixed basis gives: + + + + Using the definition #rvc-ed of + the vector derivative gives: + + + + The second-to-last line above is simply the definition + of the scalar derivative, giving the scalar derivatives + of the component functions \(a_1(t)\) and \(a_2(t)\). +

+
+ + +

+ When we differentiate a vector by differentiating each + component and leaving the basis vectors unchanged, we + are assuming that the basis vectors themselves are not + changing with time. If they are, then we need to take this into account as + well. +

+
+ + +
+

+ + +

+ + + + + + + + + + + + + +
Time: + + \(t = \) 0 s +
Show: + + + +
Basis: + + + + +
+

+ The vector derivative decomposed into components. This + demonstrates graphically that each component of a vector + in a particular basis is simply a scalar function, and the + corresponding derivative component is the regular scalar + derivative. +

+
+
@@ -559,7 +633,7 @@ import Col from "../../components/Col.astro"

-
+