Four views of rolling
// Simulation first posted on 7-20-2018 function setView(newView) { //get the element mode = Number(newView); if (mode == 1) { message1 = “View 1 – Rolling is the superposition of pure translation and pure rotation.”; message2 = “For a point on the outer edge of the wheel the translational distance”; message3 = “traveled equals the distance traveled around the edge in rotation.”; title = “Pure translation”; } if (mode == 2) { message1 = “View 2 – The net velocity (red) of a particular point is the vector sum of the”; message2 = “velocity due to translation (blue) and the velocity due to rotation (green).”; message3 = “Note that the net velocity of a point on the bottom of the wheel is zero.”; title = “Using superposition to find the net velocity at a point”; } if (mode == 3) { message1 = “View 3 – Here you can see how the velocity of a particular point on the edge”; message2 = “of a rolling wheel changes as time goes by. The translational velocity is always”; message3 = “the same, while the velocity due to rotation steadily changes direction.”; title = “See how the net velocity of a point changes as the wheel rolls”; } if (mode == 4) { message1 = “View 4 – A point on the outer edge of the wheel traces out an interesting.”; message2 = “path – the shape of this path is called a cycloid. Note that the point is”; message3 = “instantaneously at rest when it is in contact with the road.” title = “The path followed by a point on the edge of the wheel”; } reset(); } function play() { window.clearTimeout(timer); runFlag = 1; runMotion(); } function pause() { window.clearTimeout(timer); runFlag = 0; } function stepForward() { window.clearTimeout(timer); runFlag = 1; drawMotion(); } function stepBack() { window.clearTimeout(timer); index = index-2; if (index < -1) index = -1; time = index/20; xPos = xBase; runFlag = 1; drawMotion(); } function reset() { window.clearTimeout(timer); index = -1; time = 0.0; runFlag = 1; runMotion(); } var canvas = document.getElementById("myCanvas"); var context = canvas.getContext("2d"); var index = -1; var xBase = 494; // for the graph var xBase2 = 60; // for the motion var yBase = 70; // for the graph var yBase2 = 230; // for the motion var xInit = 37; var message1 = 'Choose a view to explore rolling without slipping'; var message2 = " "; var message3 = " "; var title = "Four views of rolling – use the buttons to choose a view"; var yStart = yBase+120; var plotColor = '#ff00ff'; var scenario = 1; var radius = 5; var time = 0.0; var deltat = 1/20.0; var timer; var runFlag = 1; var mode = 0; var wheelRadius = 80; var nSpokes = 20; var nArray = 600; var cycloid = new Array(nArray); for (var i = 0; i = 4000) runFlag = 0; // console.log(“In the drawMotion function, with runFlag = ” + runFlag + ” Fx = ” + Fx); if (runFlag == 1) { // run if runFlag equal 1, not if equal 0 // clear context.clearRect(0, 0, canvas.width, canvas.height); index = index + 1; // set background color for the entire thing context.fillStyle = “#ffd”; context.fillRect(0, 0, canvas.width, canvas.height); context.strokeStyle = ‘#000’; context.lineWidth = 1; // set line color context.strokeStyle = ‘#999’; context.lineWidth = 2; time = index/50.0; // xPos = vxInit*time; // yPos = vyInit*time – 0.5*g*time*time; // var vy = vyInit – g*time; // console.log(time + ‘ ‘ + xPos + ‘ ‘ + yPos); // draw the road context.beginPath(); context.strokeStyle = ‘#999’; context.lineWidth = 20; context.moveTo(50,yBase2); context.lineTo(canvas.width-50,yBase2); context.stroke(); if (mode == 0) { // draw a stationary wheel context.beginPath(); context.strokeStyle = ‘black’; context.lineWidth = 2; context.fillStyle = “#99f” context.arc(xBase2+wheelRadius, yBase2-wheelRadius-10, wheelRadius, 0, 2 * Math.PI, false); context.stroke(); context.fill(); // draw spokes for (var i = 0; i < nSpokes; i++) { context.beginPath(); context.strokeStyle = '#383'; context.lineWidth = 2; context.moveTo(xBase2+wheelRadius, yBase2-wheelRadius-10); context.lineTo(xBase2+wheelRadius+wheelRadius*Math.cos(2.0*Math.PI*i/nSpokes), yBase2-wheelRadius-10+wheelRadius*Math.sin(2.0*Math.PI*i/nSpokes)); context.stroke(); } } if (mode == 1) { // draw the moving wheel if (index 2.0*Math.PI*wheelRadius) { d = 2.0*Math.PI*wheelRadius; dIndex = Math.trunc(2.0*Math.PI*wheelRadius); } console.log(d); context.beginPath(); context.strokeStyle = ‘black’; context.lineWidth = 2; context.fillStyle = “#99f” context.arc(xBase2+wheelRadius+d, yBase2-wheelRadius-10, wheelRadius, 0, 2 * Math.PI, false); context.stroke(); context.fill(); // draw spokes for (var i = 0; i < nSpokes; i++) { context.beginPath(); context.strokeStyle = '#383'; context.lineWidth = 2; context.moveTo(xBase2+wheelRadius+d, yBase2-wheelRadius-10); context.lineTo(xBase2+wheelRadius+d+wheelRadius*Math.cos((2.0*Math.PI*i/nSpokes)), yBase2-wheelRadius-10+wheelRadius*Math.sin((2.0*Math.PI*i/nSpokes))); context.stroke(); } context.beginPath(); context.strokeStyle = "red"; context.lineWidth = 3; context.moveTo(xBase2+wheelRadius, yBase2-wheelRadius-10); context.lineTo(xBase2+wheelRadius+d, yBase2-wheelRadius-10); context.stroke(); } else if (index 2.0*Math.PI*wheelRadius) { d = 2.0*Math.PI*wheelRadius; dIndex = Math.trunc(2.0*Math.PI*wheelRadius); } console.log(d); context.beginPath(); context.strokeStyle = ‘black’; context.lineWidth = 2; context.fillStyle = “#99f” context.arc(xBase2+wheelRadius, yBase2-wheelRadius-10, wheelRadius, 0, 2 * Math.PI, false); context.stroke(); context.fill(); // draw spokes for (var i = 0; i < nSpokes; i++) { context.beginPath(); context.strokeStyle = '#383'; context.lineWidth = 2; context.moveTo(xBase2+wheelRadius, yBase2-wheelRadius-10); context.lineTo(xBase2+wheelRadius+wheelRadius*Math.cos((2.0*Math.PI*i/nSpokes)+d/wheelRadius), yBase2-wheelRadius-10+wheelRadius*Math.sin((2.0*Math.PI*i/nSpokes)+d/wheelRadius)); context.stroke(); } context.beginPath(); context.fillStyle = "red"; context.arc(xBase2+wheelRadius-wheelRadius*Math.sin(d/wheelRadius), yBase2-wheelRadius-10+wheelRadius*Math.cos(d/wheelRadius), radius, 0, 2 * Math.PI, false); context.fill(); } else if (index 2.0*Math.PI*wheelRadius) { d = 2.0*Math.PI*wheelRadius; dIndex = Math.trunc(2.0*Math.PI*wheelRadius); } console.log(d); context.beginPath(); context.strokeStyle = ‘black’; context.lineWidth = 2; context.fillStyle = “#99f”; context.arc(xBase2+wheelRadius+d, yBase2-wheelRadius-10, wheelRadius, 0, 2 * Math.PI, false); context.stroke(); context.fill(); context.beginPath(); context.strokeStyle = ‘red’; context.lineWidth = 2; context.arc(xBase2+wheelRadius+d, yBase2-wheelRadius-10, wheelRadius, 0.5*Math.PI+d/wheelRadius, 2.5 * Math.PI, false); context.stroke(); // draw spokes for (var i = 0; i 1800) { index = -1; } } if (mode == 2) { // draw a stationary wheel context.beginPath(); context.strokeStyle = ‘black’; context.lineWidth = 2; context.fillStyle = “#99f” context.arc(xBase2+wheelRadius+Math.PI*wheelRadius, yBase2-wheelRadius-10, wheelRadius, 0, 2 * Math.PI, false); context.stroke(); context.fill(); // draw spokes for (var i = 0; i 2.0*Math.PI*wheelRadius) { d = 2.0*Math.PI*wheelRadius; } console.log(d); context.beginPath(); context.strokeStyle = ‘black’; context.lineWidth = 2; context.fillStyle = “#99f” context.arc(xBase2+wheelRadius+d, yBase2-wheelRadius-10, wheelRadius, 0, 2 * Math.PI, false); context.stroke(); context.fill(); // draw spokes for (var i = 0; i 600) { index = -1; } } if (mode == 4) { // draw the moving wheel var d = index; var dIndex = index; if (d > 2.0*Math.PI*wheelRadius) { d = 2.0*Math.PI*wheelRadius; dIndex = Math.trunc(2.0*Math.PI*wheelRadius); } console.log(d); context.beginPath(); context.strokeStyle = ‘black’; context.lineWidth = 2; context.fillStyle = “#99f” context.arc(xBase2+wheelRadius+d, yBase2-wheelRadius-10, wheelRadius, 0, 2 * Math.PI, false); context.stroke(); context.fill(); // draw spokes for (var i = 0; i < nSpokes; i++) { context.beginPath(); context.strokeStyle = '#383'; context.lineWidth = 2; context.moveTo(xBase2+wheelRadius+d, yBase2-wheelRadius-10); context.lineTo(xBase2+wheelRadius+d+wheelRadius*Math.cos((2.0*Math.PI*i/nSpokes)+d/wheelRadius), yBase2-wheelRadius-10+wheelRadius*Math.sin((2.0*Math.PI*i/nSpokes)+d/wheelRadius)); context.stroke(); } context.beginPath(); context.fillStyle = "red"; context.arc(xBase2+wheelRadius+d+wheelRadius*Math.sin(d/wheelRadius), yBase2-wheelRadius-10-wheelRadius*Math.cos(d/wheelRadius), radius, 0, 2 * Math.PI, false); context.fill(); cycloid[dIndex].xValue = xBase2+wheelRadius+d+wheelRadius*Math.sin(d/wheelRadius); cycloid[dIndex].yValue = yBase2-wheelRadius-10-wheelRadius*Math.cos(d/wheelRadius); for (i=0; i 600) { index = -1; } } // console.log(“In the drawMotion function, with runFlag = ” + runFlag + ” x2 = ” + x2); context.font = ’16pt Calibri’; context.fillStyle = ‘blue’; context.textAlign = ‘left’; context.fillText(message1, xBase2, 280); context.fillText(message2, xBase2, 310); context.fillText(message3, xBase2, 340); context.font = ’16pt Calibri’; context.fillStyle = ‘purple’; context.textAlign = ‘center’; context.fillText(title, canvas.width/2, 30); } } function runMotion() { drawMotion(); if (runFlag == 1) { timer = window.setTimeout(runMotion, 500/60); } } function drawArrow(Fx,Fy,Px,Py, arrowColor) { var theta = Math.atan2(Fy,Fx); context.strokeStyle = arrowColor; context.lineWidth = 4; context.beginPath(); context.moveTo(Px, Py); context.lineTo(Px+5.0*Fx, Py-5.0*Fy); context.stroke(); context.lineWidth = 2; var Fmag = Math.sqrt(Fx*Fx+Fy*Fy); if (Fmag > 5) Fmag = 5; context.fillStyle = arrowColor; context.beginPath(); context.moveTo(Px+5.0*Fx-3*Fmag*Math.cos(theta+0.25*(Math.PI/2)),Py-5.0*Fy+3*Fmag*Math.sin(theta+0.25*(Math.PI/2))); context.lineTo(Px+5.0*Fx,Py-5.0*Fy); context.lineTo(Px+5.0*Fx-3*Fmag*Math.cos(theta-0.25*(Math.PI/2)),Py-5.0*Fy+3*Fmag*Math.sin(theta-0.25*(Math.PI/2))); context.stroke(); context.fill(); }Simulation first posted on 7-20-2018. Written by Andrew Duffy
This work by Andrew Duffy is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
This simulation can be found in the collection at http://physics.bu.edu/~duffy/classroom.html. The simulation is shared here as an archive.