{"id":579,"date":"2021-04-07T16:26:27","date_gmt":"2021-04-07T16:26:27","guid":{"rendered":"https:\/\/mathresearch.utsa.edu\/wp\/?p=579"},"modified":"2021-05-02T20:31:14","modified_gmt":"2021-05-02T20:31:14","slug":"pendulum-simulation","status":"publish","type":"post","link":"https:\/\/mathresearch.utsa.edu\/wp\/?p=579","title":{"rendered":"Double Pendulum Simulation"},"content":{"rendered":"\n<!--author@ TonyLi-->\n<!--projectname@ UTSA Visual Mathematics Research Group | Pendulum Simulation-->\n<html>\n\n<span>\n    <label>Angle 1:<\/label>\n    <input id=\"angle1Slider\" class = \"p1_slider\" type = \"range\" min = \"-90\" max = \"90\">\n<\/span>\n\n<span>\n    <label>Angle 2:<\/label>\n    <input id = \"angle2Slider\" class = \"p2_slider\" type = \"range\" min = \"-90\" max = \"90\">\n<\/span>\n\n<br>\n\n<span>\n    <label>Length 1:<\/label>\n    <input id=\"length1Slider\" class = \"p1_slider\" type = \"range\" min = \"50\" max = \"150\">\n<\/span>\n\n<span>\n    <label>Length 2:<\/label>\n    <input id=\"length2Slider\" class = \"p2_slider\" type = \"range\" min = \"50\" max = \"100\">\n<\/span>\n\n<br>\n\n<span class = \"bottom\">\n    <label>Gravity:<\/label>\n    <input id=\"gravitySlider\" type = \"range\" min = \"1\" max = \"19\">\n<\/span>\n\n<span class = \"bottom\">\n    <label>Damping:<\/label>\n    <input id=\"dampingCheckBox\" type = \"checkbox\">\n<\/span>\n\n<br>\n\n<canvas id=\"pCanvas\" width=\"600\" height=\"400\"><\/canvas> \n\n<br>\n\n<button id=\"startButton\" type = \"button\" class = \"start\">Start<\/button>\n<button id=\"resetButton\" type = \"button\" class = \"reset\">Reset<\/button>\n\n<script>\n    var pCanvas = document.getElementById(\"pCanvas\");\n    var canvas = pCanvas.getContext(\"2d\");\n    canvas.translate(300, 100);\n\n    var angle1Slider = document.getElementById(\"angle1Slider\");\n    var length1Slider = document.getElementById(\"length1Slider\");\n    var angle2Slider = document.getElementById(\"angle2Slider\");\n    var length2Slider = document.getElementById(\"length2Slider\");\n\n    \/\/draw position on screen load\n    drawPendulum(angle1Slider.value * Math.PI \/ 180, length1Slider.value, angle2Slider.value * Math.PI \/ 180, length2Slider.value);\n\n    \/\/draw initial position with user inputs\n    angle1Slider.oninput = function() {\n        drawPendulum(angle1Slider.value * Math.PI \/ 180, length1Slider.value, angle2Slider.value * Math.PI \/ 180, length2Slider.value);\n    }\n\n    length1Slider.oninput = function() {\n        drawPendulum(angle1Slider.value * Math.PI \/ 180, length1Slider.value, angle2Slider.value * Math.PI \/ 180, length2Slider.value);\n    }\n    \n    angle2Slider.oninput = function() {\n        drawPendulum(angle1Slider.value * Math.PI \/ 180, length1Slider.value, angle2Slider.value * Math.PI \/ 180, length2Slider.value);\n    }\n\n    length2Slider.oninput = function() {\n        drawPendulum(angle1Slider.value * Math.PI \/ 180, length1Slider.value, angle2Slider.value * Math.PI \/ 180, length2Slider.value);\n    }\n\n    startButton.onclick = function() {\n        var angle1 = angle1Slider.value * (Math.PI \/ 180);\n        var angle2 = angle2Slider.value * (Math.PI \/ 180);\n        var angle1_v = 0;\n        var angle1_a = 0;\n        var angle2_v = 0;\n        var angle2_a = 0;\n        var m1 = 10;\n        var m2 = 10;\n        var g = gravitySlider.value;\n        var t = 0;\n        var interval = null;\n\n        interval = setInterval(update, 1);\n        document.getElementById(\"startButton\").disabled = true;\n        document.getElementById(\"resetButton\").disabled = false;\n        document.getElementById(\"angle1Slider\").disabled = true;\n        document.getElementById(\"angle2Slider\").disabled = true;\n        document.getElementById(\"length1Slider\").disabled = true;\n        document.getElementById(\"length2Slider\").disabled = true;\n        document.getElementById(\"gravitySlider\").disabled = true;\n\n        resetButton.onclick = function() {\n            document.getElementById(\"startButton\").disabled = false;\n            document.getElementById(\"resetButton\").disabled = true;\n            document.getElementById(\"angle1Slider\").disabled = false;\n            document.getElementById(\"angle2Slider\").disabled = false;\n            document.getElementById(\"length1Slider\").disabled = false;\n            document.getElementById(\"length2Slider\").disabled = false;\n            document.getElementById(\"gravitySlider\").disabled = false;\n\n            clearInterval(interval);\n            drawPendulum(angle1Slider.value * (Math.PI \/ 180), length1Slider.value, angle2Slider.value * (Math.PI \/ 180), length2Slider.value);\n        }\n\n        function update() {\n            angle1_a = calculate_angle1_a(angle1, length1Slider.value, angle2, length2Slider.value, angle1_v, angle2_v) \/ 1000;\n            angle2_a = calculate_angle2_a(angle1, length1Slider.value, angle2, length2Slider.value, angle1_v, angle2_v) \/ 1000;\n            angle1_v += angle1_a;\n            angle2_v += angle2_a;\n            angle1 += angle1_v;\n            angle2 += angle2_v;\n\n            if(document.getElementById(\"dampingCheckBox\").checked) {\n                angle1_v *= 0.998;\n                angle2_v *= 0.998;\n                t += 0.001;\n            }\n\n            drawPendulum(angle1, length1Slider.value, angle2, length2Slider.value);\n\n            return t;\n        }\n\n        function calculate_angle1_a(angle1, L1, angle2, L2, angle1_v, angle2_v) {\n            num1 = -1 * g * (2 * m1 + m2) * Math.sin(angle1);\n            num2 = -1 * m2 * g * Math.sin(angle1 - 2 * angle2);\n            num3 = -2 * Math.sin(angle1 - angle2) * m2 * (Math.pow(angle2_v, 2) * L2 + Math.pow(angle1_v, 2) * L1 * Math.cos(angle1 - angle2));\n            den1 = L1 * (2 * m1 + m2 - m2 * Math.cos(2 * angle1 - 2 * angle2));\n\n            angle1_a = (num1 + num2 + num3) \/ (den1);\n\n            return angle1_a;\n        }\n\n        function calculate_angle2_a(angle1, L1, angle2, L2, angle1_v, angle2_v) {\n            num1 = 2 * Math.sin(angle1 - angle2);\n            num2 = (Math.pow(angle1_v, 2) * L1 * (m1 + m2));\n            num3 = g * (m1 + m2) * Math.cos(angle1);\n            num4 = Math.pow(angle2_v, 2) * L2 * m2 * Math.cos(angle1 - angle2);\n            den1 = L2 * (2 * m1 + m2 - m2 * Math.cos(2 * angle1 - 2 * angle2));\n\n            angle2_a = (num1 * (num2 + num3 + num4)) \/ (den1);\n\n            return angle2_a;\n        }\n    }\n\n    function drawPendulum(angle1, L1, angle2, L2) {\n        var x = L1 * Math.sin(angle1);\n        var y = L1 * Math.cos(angle1);\n        var x2 = L2 * Math.sin(angle2);\n        var y2 = L2 * Math.cos(angle2);\n        \n        canvas.translate(-300, -100);\n        canvas.clearRect(0, 0, pCanvas.width, pCanvas.height);\n        canvas.translate(300, 100);\n\n        canvas.beginPath(); \/\/rope for Pendulum 2\n        canvas.save();\n        canvas.lineWidth = 2.5;\n        canvas.moveTo(x + x2, y + y2);\n        canvas.lineTo(x, y);\n        canvas.closePath();\n        canvas.strokeStyle = \"#4d2600\";\n        canvas.stroke();\n        canvas.restore();\n\n        \/\/Pendulum 1\n        canvas.beginPath(); \/\/dashed line\n        canvas.save();\n        canvas.lineWidth = 1.5;\n        canvas.setLineDash([4, 5]);\n        canvas.moveTo(0, L1);\n        canvas.lineTo(0, 0)\n        canvas.closePath();\n        canvas.strokeStyle = \"#ffffff\";\n        canvas.stroke();\n        canvas.restore();\n\n        canvas.beginPath(); \/\/rope\n        canvas.save();\n        canvas.lineWidth = 3;\n        canvas.moveTo(x, y);\n        canvas.lineTo(0, 0);\n        canvas.closePath();\n        canvas.strokeStyle = '#994d00';\n        canvas.stroke();   \n        canvas.restore();\n\n        canvas.beginPath(); \/\/ball\n        canvas.save();\n        canvas.arc(x, y, 15, 0, 2 * Math.PI);\n        canvas.fillStyle = \"#e6f2ff\";\n        canvas.fill();\n        canvas.closePath();\n        canvas.restore();\n\n        canvas.beginPath(); \/\/pivot point\n        canvas.save();\n        canvas.arc(0, 0, 3, 0, 2 * Math.PI);\n        canvas.fillStyle = \"#000000\";\n        canvas.fill();\n        canvas.closePath();\n        canvas.restore();\n\n        \/\/Pendulum 2\n        canvas.beginPath(); \/\/ball\n        canvas.save();\n        canvas.arc(x + x2, y + y2, 15, 0, 2 * Math.PI);\n        canvas.fillStyle = \"#fff2e6\";\n        canvas.fill();\n        canvas.closePath();\n        canvas.restore();\n\n        canvas.font = \"13px Arial\"; \/\/values\n        canvas.fillStyle = \"#ffffff\";\n        canvas.textAlign = \"center\";\n        canvas.fillText(\"Angle 1: \" + Math.round(Math.atan(x \/ y) * (180 \/ Math.PI)) + \" degrees\", 225, -70);\n        canvas.fillText(\"Angle 2: \" + Math.round(Math.atan(x2 \/ y2) * (180 \/ Math.PI)) + \" degrees\", 225, -50);\n    }\n<\/script>\n\n<style>\n    @import url('https:\/\/fonts.googleapis.com\/css2?family=Antonio&family=Quicksand:wght@500&display=swap');\n    @import url('https:\/\/fonts.googleapis.com\/css2?family=Antonio&family=Oxygen&family=Quicksand:wght@500&display=swap');\n\n    button { \n        background-color: white;\n        color: black;\n        border-color: black;\n        border-radius: 6px;\n        border-width: 2px;\n        width: 298px;\n        padding: 6px 16px;\n        margin-right: 3px;\n        margin-top: 3px;\n        text-align: center;\n        font-size: 20px;\n        font-family: 'Antonio', sans-serif;\n        font-family: 'Quicksand', sans-serif;\n    }\n\n    button:hover {\n        background-color: #0075ff;\n        color: white;\n        border-color: white;\n        border-width: 2px;\n    }\n\n    button:disabled {\n        background-color: #cbcbcb;\n        color: white;\n        border: none;\n        border-color: white;\n        box-shadow: 5px 5px 3px inset gray, -2px -2px 2px inset #d8d8d8;\n        transform: translate(0, -20);\n    }\n    \n    h1 {\n        font-family: 'Antonio', sans-serif;\n        font-family: 'Oxygen', sans-serif;\n        font-family: 'Quicksand', sans-serif;\n    }\n\n    input[type = range] {\n        width: 150px;\n        margin-right: 5px;\n    }\n\n    input[type = checkbox] {\n        margin-bottom: 6px;\n    }\n    \n    label {\n        float: left;\n        margin-right: 5px;\n        width: 70px;\n        font-family: 'Antonio', sans-serif;\n        font-family: 'Quicksand', sans-serif;\n    }\n\n    span {\n        display: inline-block;\n        overflow: hidden;\n        padding: 0px 4px 0px 6px;\n    }\n\n    .bottom {\n        margin-bottom: 6px;\n    }\n\n    #pCanvas {\n        background-color:#003366;\n        border: 2px solid black;\n        border-radius: 6px;\n    }\n<\/style>\n\n<\/html>\n","protected":false},"excerpt":{"rendered":"<p>Angle 1: Angle 2: Length 1: Length 2: Gravity: Damping: Start Reset<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12,11],"tags":[],"class_list":["post-579","post","type-post","status-publish","format-standard","hentry","category-calculus","category-visual-math"],"_links":{"self":[{"href":"https:\/\/mathresearch.utsa.edu\/wp\/index.php?rest_route=\/wp\/v2\/posts\/579","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mathresearch.utsa.edu\/wp\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mathresearch.utsa.edu\/wp\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mathresearch.utsa.edu\/wp\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mathresearch.utsa.edu\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=579"}],"version-history":[{"count":23,"href":"https:\/\/mathresearch.utsa.edu\/wp\/index.php?rest_route=\/wp\/v2\/posts\/579\/revisions"}],"predecessor-version":[{"id":1232,"href":"https:\/\/mathresearch.utsa.edu\/wp\/index.php?rest_route=\/wp\/v2\/posts\/579\/revisions\/1232"}],"wp:attachment":[{"href":"https:\/\/mathresearch.utsa.edu\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=579"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mathresearch.utsa.edu\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=579"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mathresearch.utsa.edu\/wp\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=579"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}