{"id":400,"date":"2020-03-07T15:21:00","date_gmt":"2020-03-07T15:21:00","guid":{"rendered":"https:\/\/potatodie.nl\/diffuse-write-ups\/?p=400"},"modified":"2021-10-03T08:23:08","modified_gmt":"2021-10-03T08:23:08","slug":"bouncing-in-a-box","status":"publish","type":"post","link":"https:\/\/potatodie.nl\/diffuse-write-ups\/bouncing-in-a-box\/","title":{"rendered":"Bouncing in a box"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">This post offers solutions for<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Intersection of a parabola with a line: find the incidence point<\/li><li>Find the Bezier control point to draw section of a given parabola<\/li><li>Solve quadratic equation<\/li><\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Introduction<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">This story begins with my attempt to simulate an object bouncing around inside a box of a certain shape (a polygon). I thought that maybe this would produce some cool graphics somehow, or the bouncing object would behave in unexpected and interesting ways. <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"604\" height=\"576\" src=\"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/03\/spaghetti-1400bounces.png\" alt=\"\" class=\"wp-image-420\" srcset=\"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/03\/spaghetti-1400bounces.png 604w, https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/03\/spaghetti-1400bounces-300x286.png 300w\" sizes=\"auto, (max-width: 604px) 100vw, 604px\" \/><figcaption>Scratching the surface<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The following image shows the simulation after a few steps. The bounce is the result of a gravitational force exerted on the object.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"614\" height=\"587\" src=\"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/03\/spaghetti-14bounces.png\" alt=\"\" class=\"wp-image-417\" srcset=\"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/03\/spaghetti-14bounces.png 614w, https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/03\/spaghetti-14bounces-300x287.png 300w\" sizes=\"auto, (max-width: 614px) 100vw, 614px\" \/><figcaption>Trajectory of a point after a few bounces.<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">To draw this it&#8217;s necessary to find out the position of the next bounce. Also, the position where the object would hit a polygon edge. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The bouncing point describes parabolas, while the edges of the polygon are line segments. So the problem is: Find the point where a given parabola intersects a given line.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Parametric representations<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Consider a parabola with the following parametric representation<\/p>\n\n\n\n<div class=\"wp-block-katex-display-block katex-eq\" data-katex-display=\"true\"><pre>\\tag{1}k(t) = p + vt + \\tfrac{1}{2}at^2<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">with (known) vectors <em>p, v<\/em> and <em>a.<\/em> Here<em> p <\/em>stands for the position at<em> t <\/em>= 0, <em>v<\/em> for velocity at <em>t<\/em> = 0, and <em>a <\/em>for the accelaration.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Next, there&#8217;s a line, parameterized by <em>s<\/em>,<\/p>\n\n\n\n<div class=\"wp-block-katex-display-block katex-eq\" data-katex-display=\"true\"><pre>\\tag{2}l(s) = q + rs<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">with vectors <em>q<\/em> and <em>r.<\/em> If we restrict <em>s<\/em> to  0 \u2264 <em>s <\/em> \u2264 1, then we&#8217;re looking at the line segment between <em>q<\/em> and <em>q<\/em> + <em>r<\/em>. (A nicer parametrization would be <em>q(s-1) + rs, <\/em>for the line segment between <em>q<\/em> and <em>r<\/em>, but that would make the following formulas a bit longer.)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Equating the parabola and the line, and separating for <em>x <\/em>and <em>y <\/em>coordinates, we get<\/p>\n\n\n\n<div class=\"wp-block-katex-display-block katex-eq\" data-katex-display=\"true\"><pre>\\tag{3}p_x + v_xt + \\tfrac{1}{2}a_xt^2= q_x +r_xs\n\n<\/pre><\/div>\n\n\n\n<div class=\"wp-block-katex-display-block katex-eq\" data-katex-display=\"true\"><pre>\\tag{4}\np_y + v_yt + \\tfrac{1}{2}a_yt^2 = q_y + r_ys<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Solving (3) for <em>s,<\/em> with <em>r<sub>x<\/sub><\/em> \u2260 0,<\/p>\n\n\n\n<div class=\"wp-block-katex-display-block katex-eq\" data-katex-display=\"true\"><pre>\\tag{5}\ns = \\dfrac{p_x - q_x + v_xt +\\tfrac{1}{2}a_xt^2} {r_x}<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Then substitute this result for <em>s <\/em>in (4). This leads to a quadratic equation, <\/p>\n\n\n\n<div class=\"wp-block-katex-display-block katex-eq\" data-katex-display=\"true\"><pre>\\tfrac{1}{2}(a_y - \\frac{r_y}{r_x}a_x)t^2+ (v_y-\\frac{r_y}{r_x}v_x)t+p_y-q_y-\\frac{r_y}{r_x}(p_x-q_x) = 0<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">from which one, two or zero solutions for <em>t<\/em> can be found. See below for an algorithm that will do that for you.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A solution for <em>t<\/em> means we can calculate the incidence point of the parabola and the line, using (1).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If there are solutions for <em>t, <\/em>calculate <em>s<\/em> using (5). Checking if  0 \u2264 <em>s <\/em> \u2264 1  it follows whether the parabola hits the line segment between <em>r<\/em> and <em>q<\/em> + <em>r <\/em>or misses it. The incidence point(s) then follow either from (1) or (2). <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We assumed above that <em>r<sub>x<\/sub><\/em> \u2260 0. Otherwise (3) will lead to a quadratic equation from which <em>t<\/em> can be found.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Looking for the Bezier control point<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">At this stage, we have the begin and end positions (let&#8217;s call them <em>p<\/em> and <em>q<\/em>) lying on the parabola with parametrization (I repeat)<\/p>\n\n\n\n<div class=\"wp-block-katex-display-block katex-eq\" data-katex-display=\"true\"><pre>k(t) = p + vt + \\tfrac{1}{2}at^2<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">We also have the speed vectors <em>v<\/em> and <em>w<\/em>, and we know the value of parameter <em>t<\/em> at position <em>p<\/em> and <em>q<\/em> (resp. 0 and <em>t<sub>q<\/sub><\/em>).<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"840\" height=\"1024\" src=\"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/03\/control_point-840x1024.jpg\" alt=\"\" class=\"wp-image-423\" srcset=\"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/03\/control_point-840x1024.jpg 840w, https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/03\/control_point-246x300.jpg 246w, https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/03\/control_point-768x936.jpg 768w, https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/03\/control_point-1260x1536.jpg 1260w, https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/03\/control_point-1680x2048.jpg 1680w, https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/03\/control_point-1200x1463.jpg 1200w, https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/03\/control_point-1980x2414.jpg 1980w\" sizes=\"auto, (max-width: 840px) 100vw, 840px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">So the following formulas hold:<\/p>\n\n\n\n<div class=\"wp-block-katex-display-block katex-eq\" data-katex-display=\"true\"><pre>\\tag{6}\nq = p + vt_q + \\tfrac{1}{2}at_q^2<\/pre><\/div>\n\n\n\n<div class=\"wp-block-katex-display-block katex-eq\" data-katex-display=\"true\"><pre>\\tag{7}\nw = v + at_q<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">To draw the parabola from <em>p<\/em> to <em>q<\/em> on a canvas context as a quadratic Bezier curve we need to find the control point <em>cp<\/em>. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The control point is the incidence point of the line <em>l <\/em>through <em>p<\/em> with direction <em>v<\/em>, and the line <em>m <\/em>through <em>q<\/em> with direction <em>w<\/em>, see image above. We could find the incidence point of <em>l <\/em>and <em>m <\/em>with a general algorithn, however in this case there is an easier method.<em> <\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The point<\/p>\n\n\n\n<div class=\"wp-block-katex-display-block katex-eq\" data-katex-display=\"true\"><pre>p + \\tfrac{1}{2}t_qv<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"> lying on <em>l<\/em>, and <\/p>\n\n\n\n<div class=\"wp-block-katex-display-block katex-eq\" data-katex-display=\"true\"><pre>q - \\tfrac{1}{2}t_qw<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">lying on <em>m<\/em>, can be shown to coincide by substituting (6) and (7). So that must be the control point we are after.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The JavaScript code to render the graphics would look like this:<\/p>\n\n\n<div class=\"wp-block-advanced-gutenberg-blocks-code\">\n  <header class=\"wp-block-advanced-gutenberg-blocks-code__header\">\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__lang is-lang-js\">\n      JS    <\/div>\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__file\">\n          <\/div>\n  <\/header>\n  <textarea \n    class=\"wp-block-advanced-gutenberg-blocks-code__source\" \n    name=\"codemirror-1852255537\" \n    id=\"codemirror-1852255537\"\n  >ctx.beginPath();\nctx.moveTo(p.x,p.y);\nctx.quadraticCurveTo(\n    p.x + v.x * t_q \/ 2, \n    p.y + v.y * t_q \/ 2,\n    q.x, \n    q.y\n);\nctx.stroke();<\/textarea>\n  <script>\n    CodeMirror.fromTextArea( document.getElementById('codemirror-1852255537'), {\n      mode: 'javascript',\n      readOnly: true,\n      theme: 'hopscotch', \n      lineNumbers: true,\n      firstLineNumber: 1,\n      matchBrackets: true,\n      indentUnit: 4,\n      tabSize: 4,\n      lineWrapping: true,\n    } ); \n  <\/script>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The following image shows the first bounces together with their control points (in pink).<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"386\" height=\"394\" src=\"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/03\/bounces.png\" alt=\"\" class=\"wp-image-426\" srcset=\"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/03\/bounces.png 386w, https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/03\/bounces-294x300.png 294w\" sizes=\"auto, (max-width: 386px) 100vw, 386px\" \/><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\">What&#8217;s left out<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Apart from finding incidence points of a parabola with a line and finding control points of Bezier curves, there are a few more steps to complete the bouncing in a box example.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">One thing I omittted is that to follow the trajectory of the bouncing object we need to find the first edge the parabola would hit. This means searching for the incidence point with the smallest positive <em>t.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Another omission is calculating the new speed vector at a bouncing point.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If your interested in these steps, check the code in the <a href=\"https:\/\/github.com\/potatoDie\/bounce-in-a-box\">github repository<\/a>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Appendix: Solve quadratic equation<\/h4>\n\n\n<div class=\"wp-block-advanced-gutenberg-blocks-code\">\n  <header class=\"wp-block-advanced-gutenberg-blocks-code__header\">\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__lang is-lang-js\">\n      JS    <\/div>\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__file\">\n          <\/div>\n  <\/header>\n  <textarea \n    class=\"wp-block-advanced-gutenberg-blocks-code__source\" \n    name=\"codemirror-193241992\" \n    id=\"codemirror-193241992\"\n  >solveQuadraticEquation: function (a, b, c) {\n    if (a == 0) {\n        \/\/ If a equals zero, it&#039;s not a quadratic \n        \/\/ equation. You may solve it\n        \/\/ anyway, if b is not also zero.\n        return b != 0 ? [-c\/b] : [];\n    }\n\n    var D = b * b - 4 * a * c; \/\/ The discriminant\n    if (D &lt; 0) {\n        return [];\n    } else if (D == 0) {\n        return [ -b \/ (2 * a)];\n    } else {\n        return [\n            (-b - Math.sqrt(D)) \/ (2 * a), \n            (-b + Math.sqrt(D)) \/ (2 * a)\n        ];\n    }\n}<\/textarea>\n  <script>\n    CodeMirror.fromTextArea( document.getElementById('codemirror-193241992'), {\n      mode: 'javascript',\n      readOnly: true,\n      theme: 'hopscotch', \n      lineNumbers: true,\n      firstLineNumber: 1,\n      matchBrackets: true,\n      indentUnit: 4,\n      tabSize: 4,\n      lineWrapping: true,\n    } ); \n  <\/script>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>How to intersect a parabola with a line, and other graphics solutions.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[30,50,29],"tags":[31],"class_list":["post-400","post","type-post","status-publish","format-standard","hentry","category-geometry","category-graphics","category-mathematics","tag-bezier"],"acf":[],"_links":{"self":[{"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/posts\/400","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/comments?post=400"}],"version-history":[{"count":20,"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/posts\/400\/revisions"}],"predecessor-version":[{"id":998,"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/posts\/400\/revisions\/998"}],"wp:attachment":[{"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/media?parent=400"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/categories?post=400"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/tags?post=400"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}