|
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);
}