Theta = 45
cos(Theta) = 0.707 sin(Theta) = 0.707 |
Angle:
ctx.rotate(35) // rotation matrix R ctx.translate(50,20) // translate matrix T ctx.scale(3,0.9) // scale matrix S ctx.strokeRect(10, 20, 5, 5);
Angle: | |
Translate X: Y: | |
Scale X: Y: | |
Order: | |
Angle = 45
Step Size: 0 Old x = 0, New x = 0.707 Old y = 0, New y = 0.707 |
Angle:
<head> <script type="text/javascript" async src="trig.js"> </script> <script type="text/javascript" async src="trans.js"> </script> <script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js"></script> <script type="text/javascript" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML"> </script> <script type="text/x-mathjax-config"> MathJax.Hub.Config({tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]}}); </script> <link rel="stylesheet" href="http://mirkwood.cs.edinboro.edu/~bennett/style/hw.css"> </head> <body> <h1> Some Math</h1> <ul> <li> The <a href="http://mirkwood.cs.edinboro.edu/~bennett/f360-19/arrow/">goal</a> <li> Some of this is from page 175+ in the book. <li> A point in 2 space is represented as a triple <ul> <li> (x,y) => [x,y,1] </ul> <li> Remember vector matrix multiplication <ul> <li> $a = \begin{bmatrix} x \\ y \\ 1 \end{bmatrix}$ <li> $T = \begin{bmatrix} a & b & c \\ d & e & f \\ g & h & i \end{bmatrix}$ <li> $ T \times a = \begin{bmatrix} a & b & c \\ d & e & f \\ g & h & i \end{bmatrix} \times \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} = \begin{bmatrix} ax + by + c & dx + ey + f & gx + hy + i\end{bmatrix}$ </ul> <li> Remember matrix matrix multiplication <ul> <li> $ A \times B \ne B \times A$ </ul> <li> Translate shifts the entire plane by the amount given. <ul> <li> $x_{new} = x_{old} + t_x$ <li> $y_{new} = y_{old} + t_y$ <li> $ T = \begin{bmatrix} 1 & 0 & t_x \\ 0 & 1 & t_y \\ 0 & 0 & 1 \end{bmatrix}$ </ul> <li> Scale shrinks or grows every point by the given amount <ul> <li> $x_{new} = x_{old} \times s_x$ <li> $y_{new} = y_{old} \times s_y$ <li> $ S = \begin{bmatrix} s_x & 0 & 0 \\ 0 & s_y & 0 \\ 0 & 0 & 1 \end{bmatrix}$ </ul> <li> Rotate rotates the entire plane about 0 by a given angle. <ul> <li> The math is a bit more complex. <lI> We will discuss it later. <li> $x_{new} = x_{old} \times \cos\theta - y_{old} \times \sin\theta $ <li> $x_{new} = x_{old} \times \sin\theta + y_{old} \times \cos\theta $ <li> $ R = \begin{bmatrix} \cos\theta & -\sin\theta & 0 \\ \sin\theta & \cos\theta & 0 \\ 0 & 0 & 1 \end{bmatrix}$ </ul> <li> But what are these cos and sin things? <ul> <li> In a triangle <table > <tr> <td> <canvas id="tri1" width=200 height=200 style="border:2px solid"></canvas> </td><td> <div id="output"> <span> Theta = 45 <p> cos(Theta) = 0.707 <p> sin(Theta) = 0.707 </span> </div> </td></tr> </table> <p> Angle: <input type="text" maxLength = "4" size = "4" id="angle" onchange ="DoTri()"> <p> </ul> <script> 'use strict' var canvas = document.getElementById('tri1'); var ctx = canvas.getContext('2d'); document.getElementById('angle').value = 45; DoTri(); </script> <p> <li> So how does this work. <ul> <li> In the HTML5 canvas the context contains a Transformation Matrix $M$ <ul> <li> This is initialized to the identity matrix <li> $M = \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{bmatrix}$ <li> When a specific transformation (X) is applied, M is multiplied by that matrix in the form $M = M \times X$ <li> Or you can think of a series of transformations like this <li> $M = I \times X_1 \times X_2 \cdots \times X_n$ </uL> <li> When a point is "drawn", the transformation matrix is applied <ul> <li> $v_1' = M \times v_1$ <li> This is equivalent to <li> $ I \times X_1 \times X_2 \cdots \times X_n \times v_1$ <li> Or $X_n$ is applied to $v_1$, <li> then $X_{n-1}$ and so on. <li> This is applied to all points. </ul> <li> So the following code <ul> <li> <pre class="prettyprint"> ctx.rotate(35) // rotation matrix R ctx.translate(50,20) // translate matrix T ctx.scale(3,0.9) // scale matrix S ctx.strokeRect(10, 20, 5, 5); </pre> <li> The transformation matrix will be $M = IRTS$ <li> The computations will be <ul> <li> $M \times \begin{bmatrix} 10 \\ 20 \\ 1\end{bmatrix} $ <li> which will <ol TYPE=A> <li> Scale that point by 3,0.9 <lI> Then Translate that point by 50,20 <lI> Then Rotate about the origin by 35 degrees </ol> <li> To produce the final coordinate to be displayed <li> The same will happen for <ul> <li> $M \times \begin{bmatrix} 15 \\ 25 \\ 1\end{bmatrix} $ </ul> </ul> </ul> <li> One more thing: <ul> <li> <a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Transformations#Transforms">ctx.transform()</a> <ul> <li> Will allow us to apply whatever transformation matrix we want. <lI> Well sort of, the parameters are (a,b,c,d,e,f) <li> And this forms the matrix <li> $M = \begin{bmatrix} a & c & e \\ b & d & f \\ 0 & 0 & 1 \end{bmatrix}$ </ul> <li> We really would like to reflect the entire picture about the line y=height/2 <ul> <li> So this can be accomplished with <li> $M = \begin{bmatrix} 1 & 0 & 0 \\ 0 & -1 & h \\ 0 & 0 & 1 \end{bmatrix}$ <li> $M \times \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} = (x , h-y, 1)$ </ul> </ul> <p> <table> <tr><td rowspan = 5> <canvas id="trans" width=200 height=200 style="border:2px solid"></canvas> </td> <td> Angle: <input type="text" maxLength = "4" size = "4" id="transAngle"> </td></tr> <tr><td> Translate X: <input type="text" maxLength = "4" size = "4" id="transX"> Y: <input type="text" maxLength = "4" size = "4" id="transY"> </td></tr> <tr><td> Scale X: <input type="text" maxLength = "4" size = "4" id="scaleX"> Y: <input type="text" maxLength = "4" size = "4" id="scaleY"> </td></tr> <tr><td> Order: <select id="transOrder"> <option value="RST">Rotate Scale Translate</option> <option value="RTS" selected >Rotate Translate Scale </option> <option value="SRT">Scale Rotate Translate </option> <option value="STR">Scale Translate Rotate </option> <option value="TRS">Translate Rotate Scale </option> <option value="TSR">Translate Scale Rotate </option> </select> </td></tr> <tr><td> <button type="button" id="redraw" onclick="TransRedisplay()">Redraw</button> </td></tr> </table> <script> var tcanvas = document.getElementById('trans'); var tctx = tcanvas.getContext('2d'); tctx.transform(1,0,0,-1,0,tcanvas.height); var tRotate = 35; var tTranslate = [50,20]; var tScale = [3,0.9]; document.getElementById('transAngle').value = tRotate; document.getElementById('transX').value = tTranslate[0]; document.getElementById('transY').value = tTranslate[1]; document.getElementById('scaleX').value = tScale[0]; document.getElementById('scaleY').value = tScale[1]; TransRedisplay(); </script> </ul> <li> The unit circle <ul> <li> Given an angle θ and a radius r, we can compute the position of a point in cartesian space using <ul> <li> $ x = r \cos\theta $ <li> $ y = r \sin\theta $ <table > <tr> <td> <canvas id="uc" width=200 height=200 style="border:2px solid"></canvas> </td><td> <div id="ucoutput"> <span> Angle = 45 <p> Step Size: 0 <p> Old x = 0, New x = 0.707 <p> Old y = 0, New y = 0.707 </span> </div> </td></tr> </table> <p> Angle: <input type="text" maxLength = "4" size = "4" id="ucangle" onchange ="DoUC()"> </ul> <script> 'use strict' var uccanvas = document.getElementById('uc'); var uctx = uccanvas.getContext('2d'); var radius = Math.floor(.4*Math.min(uccanvas.width, uccanvas.height)) var xc = uccanvas.width/2; var yc = uccanvas.height/2; document.getElementById('ucangle').value = 45; DoUC(); </script> </ul> </ul> </body>
'use strict' function DrawFigure(color, step) { // draw the happy man tctx.strokeStyle = color; tctx.fillStyle = "yellow"; tctx.beginPath(); tctx.arc(40,40,10,0,Math.PI * 2); tctx.stroke(); tctx.fill(); tctx.moveTo(40,30); tctx.lineTo(40,10); tctx.lineTo(30,0); tctx.moveTo(40,10); tctx.lineTo(50,0); tctx.moveTo(30,25); tctx.lineTo(50,25); tctx.stroke(); tctx.closePath(); tctx.beginPath(); tctx.strokeText(step, 45, 20); } function ApplyTransform(letter) { switch(letter) { case 'R': tctx.rotate(tRotate * Math.PI/180); break; case 'S': tctx.scale(tScale[0],tScale[1]); break; case 'T': tctx.translate(tTranslate[0],tTranslate[1]); break; } } function TransRedisplay() { let colors = ['red','green', 'blue']; tRotate = document.getElementById('transAngle').value; tTranslate[0] = document.getElementById('transX').value; tTranslate[1] = document.getElementById('transY').value; tScale[0] = document.getElementById('scaleX').value; tScale[1] = document.getElementById('scaleY').value; let order = document.getElementById("transOrder").value; tctx.clearRect(0,0,tcanvas.width, tcanvas.height); tctx.save(); // draw the untransformed figure DrawFigure("black","A"); for (let i=0;i<order.length;i++) { ApplyTransform(order[i]); DrawFigure(colors[i],order[i]); } tctx.restore(); }
'use strict' function Circle(ox, oy, r) { let holdColor = ctx.strokeStyle; ctx.strokeStyle= "blue"; ctx.beginPath(); ctx.moveTo(ox,oy); ctx.arc(ox, oy, r, 0, -Math.PI/2,true); ctx.closePath(); ctx.stroke(); ctx.strokeStyle = holdColor; } function Triangle(ox, oy, x,y) { ctx.beginPath(); ctx.moveTo(ox,oy); ctx.lineTo(x,oy); ctx.lineTo(x, y) ctx.lineTo(ox,oy); ctx.stroke(); ctx.closePath(); } function DoOutput(theta) { let text = "Theta = " + -theta; text = text + "<p>cos(Theta) = " + Math.cos(-theta * Math.PI/180).toFixed(3); text = text + "<p>sin(Theta) = " + Math.sin(-theta * Math.PI/180).toFixed(3); document.getElementById('output').innerHTML = text; } function LabelTheta(ox, oy, x, y, radius, theta) { let holdColor = ctx.strokeStyle; ctx.strokeStyle= "red"; let newRadius = Math.min(radius/2, (x-ox)/2) let divisor = 3/2; if (theta > -20) { divisor = 3/4; } else if (theta < -30) { divisor = 3; } let tx = ox + newRadius/divisor * Math.cos(theta/2*Math.PI/180); let ty = oy + newRadius/divisor * Math.sin(theta/2*Math.PI/180); ctx.beginPath(); ctx.moveTo(tx,ty); let text = String(-theta); ctx.fillText(text, tx, ty); ctx.beginPath(); ctx.arc(ox, oy, newRadius, 0, theta * Math.PI/180, true); ctx.stroke(); ctx.moveTo(ox/2, oy/2) ctx.closePath(); ctx.strokeStyle = holdColor; } function GetTheta() { let theta = parseInt(document.getElementById('angle').value); if (! typeof theta === 'number') { theta = 45; } if (theta < 0 || theta > 90) { theta = 45; } document.getElementById('angle').value = theta; return -theta; } function DoTri() { ctx.clearRect(0,0,canvas.width,canvas.height); let theta = GetTheta(); let dim = Math.min(canvas.width, canvas.height); let r = (dim - 20 ) let ox = 10; let oy = canvas.height-10; let x = ox + r * Math.cos(theta * Math.PI/180); let y = oy + r * Math.sin(theta * Math.PI/180); DoOutput(theta); LabelTheta(ox,oy, x, y, r, theta); Circle(ox,oy,r); Triangle(ox,oy,x,y); } function DoUCOutput(theta) { let text = "Angle = " + theta; text = text + "<p>Step Size = " + radius ; text = text + "<p>Old x = " + xc + ", New x = " + Math.floor(xc + radius * Math.cos(-theta * Math.PI/180)); text = text + "<p>Old y = " + yc + ", New y = " + Math.floor(yc - radius * Math.sin(-theta * Math.PI/180)) document.getElementById('ucoutput').innerHTML = text; } function DoUC() { let theta = parseInt(document.getElementById('ucangle').value); let x = xc + radius * Math.cos(theta*Math.PI/180); let y = yc - radius * Math.sin(theta*Math.PI/180); uctx.clearRect(0,0,uccanvas.width, uccanvas.height); // draw the unit circle uctx.beginPath() uctx.strokeStyle = "blue"; uctx.arc(xc, yc, radius, 0, 2*Math.PI); uctx.stroke(); uctx.closePath(); // draw a circle at the center uctx.beginPath(); uctx.fillStyle = "green"; uctx.arc(xc, yc, 5, 0, 2*Math.PI); uctx.fill(); uctx.closePath(); // draw a circle at the next step. uctx.beginPath(); uctx.fillStyle = "green"; uctx.arc(x, y, 5, 0, 2*Math.PI); uctx.fill(); uctx.closePath(); DoUCOutput(theta); }