Added the rest of the files
This commit is contained in:
343
rainbow2.html
Normal file
343
rainbow2.html
Normal file
@@ -0,0 +1,343 @@
|
||||
<!--
|
||||
This work is licensed under CC BY-NC-ND 4.0
|
||||
Link to license: http://creativecommons.org/licenses/by-nc-nd/4.0/
|
||||
Attribute to Russell Georgi
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Waves: Rainbow 2
|
||||
</title>
|
||||
<style>
|
||||
html, body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0px;
|
||||
border: 0;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
}
|
||||
|
||||
canvas {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
form {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.slideContainer {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="myCanvas" width="1" height="1" style="border:1px solid #ffffff;">
|
||||
Your browser does not support the HTML5 canvas tag.</canvas>
|
||||
<form>
|
||||
<label for="red">Red</label>
|
||||
<input type="checkbox" id="red" onclick="redClick()">
|
||||
<br>
|
||||
<label for="blue">Blue</label>
|
||||
<input type="checkbox" id="blue" onclick="blueClick()">
|
||||
</form>
|
||||
<div class="slidecontainer">
|
||||
<t>Ray density</t>
|
||||
<input type="range" min="0.09" max="0.2" value="0.14" step = "0.003" id="slider">
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
class Vector2 {
|
||||
constructor (x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
scale(n)
|
||||
{
|
||||
this.x *= n;
|
||||
this.y *= n;
|
||||
}
|
||||
|
||||
get len()
|
||||
{
|
||||
return this.calcLen();
|
||||
}
|
||||
|
||||
calcLen()
|
||||
{
|
||||
return (Math.sqrt(this.x * this.x + this.y * this.y));
|
||||
}
|
||||
}
|
||||
|
||||
class Circle {
|
||||
constructor (x, y, r)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.r = r;
|
||||
}
|
||||
}
|
||||
|
||||
var c = document.getElementById("myCanvas");
|
||||
var ctx = c.getContext("2d");
|
||||
ctx.canvas.width = window.innerWidth;
|
||||
ctx.canvas.height = window.innerHeight;
|
||||
|
||||
var nn = 1.35;
|
||||
var r = 25;
|
||||
var cl4 = "#ff0000";
|
||||
var cl17 = "#0000ff";
|
||||
var cl15 = "#000000";
|
||||
var red = false;
|
||||
var blue = false;
|
||||
var dtog = 0;
|
||||
var x0 = 0;
|
||||
var y0 = 60;
|
||||
var x1 = 0;
|
||||
var y1 = -60;
|
||||
var dy = 10;
|
||||
var nnn = 50;
|
||||
var maxSteps = 18000;
|
||||
var reflections = 0;
|
||||
var maxReflections = 1;
|
||||
var step = r / 10;
|
||||
var xPos = 0;
|
||||
var yPos = 0;
|
||||
var red = false;
|
||||
var blue = false;
|
||||
var density = 0.14;
|
||||
var circles = [];
|
||||
|
||||
slider.oninput = function()
|
||||
{
|
||||
density = parseFloat(this.value);
|
||||
console.log(density);
|
||||
Update();
|
||||
}
|
||||
|
||||
ctx.translate(ctx.canvas.width / 2, ctx.canvas.height / 2);
|
||||
ctx.scale(1.5, -1.5);
|
||||
|
||||
function Clear(ctx)
|
||||
{
|
||||
ctx.clearRect(-c.width, -c.height, c.width * 2, c.height * 2);
|
||||
}
|
||||
|
||||
function Update()
|
||||
{
|
||||
Clear(ctx);
|
||||
ctx.strokeStyle = "#000000";
|
||||
ctx.beginPath();
|
||||
ctx.arc(xPos + x0, yPos + y0, r, 0, Math.PI * 2);
|
||||
ctx.stroke();
|
||||
circles.push(new Circle(x0, y0, r));
|
||||
ctx.beginPath();
|
||||
ctx.arc(xPos + x1, yPos + y1, r, 0, Math.PI * 2);
|
||||
ctx.stroke();
|
||||
ctx.scale(1, -1);
|
||||
ctx.fillText("Light from one reflection", -150, -30);
|
||||
ctx.fillText("Light from two reflections", -50, 130);
|
||||
ctx.fillText("Dark band", -155, 140);
|
||||
ctx.scale(1, -1);
|
||||
circles.push(new Circle(x1, y1, r));
|
||||
for (h2 = 0; h2 <= 1; h2 += density)
|
||||
{
|
||||
if (h2 != 0 && h2 < 0.99999)
|
||||
{
|
||||
if (red)
|
||||
{
|
||||
maxReflections = 1;
|
||||
Ray(new Vector2(1 - c.width, h2 * r + y0), new Vector2(1, 0), 1, 1.332, "#ff0000");
|
||||
maxReflections = 2;
|
||||
Ray(new Vector2(1 - c.width, - h2 * r + y1), new Vector2(1, 0), 1, 1.332, "#ff0000");
|
||||
}
|
||||
if (blue)
|
||||
{
|
||||
maxReflections = 1;
|
||||
Ray(new Vector2(1 - c.width, h2 * r + y0), new Vector2(1, 0), 1, 1.35, "#0000ff");
|
||||
maxReflections = 2;
|
||||
Ray(new Vector2(1 - c.width, - h2 * r + y1), new Vector2(1, 0), 1, 1.35, "#0000ff");
|
||||
}
|
||||
}
|
||||
}
|
||||
/*Ray(new Vector2(1 - c.width, 2 * r / 3 + y0), new Vector2(1, 0.00), 1, 1.332, "#ff0000");
|
||||
//Ray(new Vector2(r / 2, c.height - 1), new Vector2(-0.03, -1), 0.1, 1.332, "#ff0000");
|
||||
Ray(new Vector2(1 - c.width, 2 * r / 3 + y0), new Vector2(1, 0.00), 1, 1.35, "#0000ff");
|
||||
maxReflections = 2;
|
||||
Ray(new Vector2(1 - c.width, - 15 * r / 16 + y1), new Vector2(1, 0.00), 1, 1.332, "#ff0000");
|
||||
//Ray(new Vector2(r / 2, c.height - 1), new Vector2(-0.03, -1), 0.1, 1.332, "#ff0000");
|
||||
Ray(new Vector2(1 - c.width, - 15 * r / 16 + y1), new Vector2(1, 0.00), 1, 1.35, "#0000ff");
|
||||
//setTimeout(Update, 1000/60);*/
|
||||
}
|
||||
|
||||
function Ray(startPos, startDir, distStep, nCircle, color)
|
||||
{
|
||||
pos = startPos;
|
||||
dir = startDir;
|
||||
n = 1;
|
||||
nLastStep = 1;
|
||||
nSteps = 0;
|
||||
reflections = 0;
|
||||
circlePos = new Vector2(0, 0);
|
||||
for (i = 0; i < circles.length; i++)
|
||||
{
|
||||
dist = Math.sqrt(Math.pow(pos.x - circles[i].x, 2) + Math.pow(pos.y - circles[i].y, 2));
|
||||
if (dist < r)
|
||||
{
|
||||
n = nCircle;
|
||||
circlePos = new Vector2(circles[i].x, circles[i].y);
|
||||
}
|
||||
}
|
||||
while (Math.abs(pos.x) <= c.width && Math.abs(pos.y) <= c.height && nSteps <= maxSteps)
|
||||
{
|
||||
nSteps += 1;
|
||||
|
||||
nCurrent = 1;
|
||||
for (i = 0; i < circles.length; i++)
|
||||
{
|
||||
dist = Math.sqrt(Math.pow(pos.x - circles[i].x, 2) + Math.pow(pos.y - circles[i].y, 2));
|
||||
if (dist < r)
|
||||
{
|
||||
nCurrent = nCircle;
|
||||
circlePos = new Vector2(circles[i].x, circles[i].y);
|
||||
}
|
||||
}
|
||||
if (nCurrent != n && nCurrent != nLastStep)
|
||||
{
|
||||
if (nCurrent < n && reflections < maxReflections)
|
||||
{
|
||||
dir = calculateReflectedDir(dir, pos, n, nCurrent, circlePos);
|
||||
reflections += 1;
|
||||
} else
|
||||
{
|
||||
dir = calculateRefractedDir(dir, pos, n, nCurrent, circlePos);
|
||||
}
|
||||
//console.log(dir, nCurrent, nSteps);
|
||||
}
|
||||
nLastStep = n;
|
||||
n = nCurrent;
|
||||
ctx.strokeStyle = color;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(pos.x, pos.y);
|
||||
ctx.lineTo(pos.x + dir.x * distStep, pos.y + dir.y * distStep);
|
||||
ctx.stroke();
|
||||
pos.x += dir.x * distStep;
|
||||
pos.y += dir.y * distStep;
|
||||
}
|
||||
}
|
||||
|
||||
function calculateRefractedDir(dir, pos, n1, n2, cPos)
|
||||
{
|
||||
//console.log("recalc");
|
||||
posToCircle = new Vector2(pos.x - cPos.x, pos.y - cPos.y);
|
||||
circleNormal = new Vector2(-posToCircle.x / posToCircle.len, -posToCircle.y / posToCircle.len);
|
||||
/*ctx.strokeStyle = "#000000";
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(pos.x + circleNormal.x * 10, pos.y + circleNormal.y * 10);
|
||||
ctx.lineTo(pos.x - circleNormal.x * 10, pos.y - circleNormal.y * 10);
|
||||
ctx.stroke();*/
|
||||
if (n1 > n2)
|
||||
{
|
||||
circleNormal.x *= -1;
|
||||
circleNormal.y *= -1;
|
||||
}
|
||||
theta1 = Math.acos((dir.x * circleNormal.x + dir.y * circleNormal.y) / (dir.len * circleNormal.len));
|
||||
theta2 = Math.asin(n1 * Math.sin(theta1) / n2);
|
||||
angle = theta2 - theta1;
|
||||
angleDiff = polarCoords(dir).y - polarCoords(new Vector2(circleNormal.x, circleNormal.y)).y;
|
||||
//console.log("calculate", angleDiff);
|
||||
if (Math.abs(angleDiff) > 90)
|
||||
{
|
||||
angleDiff *= -1;
|
||||
}
|
||||
if (angleDiff < 0)
|
||||
{
|
||||
//console.log("flipr")
|
||||
angle *= -1;
|
||||
}
|
||||
//console.log(angle, dir.x, dir.y, posToCircle.x, posToCircle.y, theta1, theta2);
|
||||
return new Vector2(dir.x * Math.cos(angle) - dir.y * Math.sin(angle), dir.x * Math.sin(angle) + dir.y * Math.cos(angle));
|
||||
}
|
||||
|
||||
function calculateReflectedDir(dir, pos, n1, n2, cPos)
|
||||
{
|
||||
//console.log("reflect");
|
||||
posToCircle = new Vector2(pos.x - cPos.x, pos.y - cPos.y);
|
||||
circleNormal = new Vector2(-posToCircle.x / posToCircle.len, -posToCircle.y / posToCircle.len);
|
||||
ctx.strokeStyle = "#000000";
|
||||
/*ctx.beginPath();
|
||||
ctx.moveTo(pos.x + circleNormal.x * 10, pos.y + circleNormal.y * 10);
|
||||
ctx.lineTo(pos.x - circleNormal.x * 10, pos.y - circleNormal.y * 10);
|
||||
ctx.stroke();*/
|
||||
if (n1 > n2)
|
||||
{
|
||||
circleNormal.x *= -1;
|
||||
circleNormal.y *= -1;
|
||||
}
|
||||
theta1 = Math.acos((dir.x * circleNormal.x + dir.y * circleNormal.y) / (dir.len * circleNormal.len));
|
||||
angle = Math.PI - 2 * theta1
|
||||
angleDiff = polarCoords(dir).y - polarCoords(new Vector2(circleNormal.x, circleNormal.y)).y;
|
||||
//console.log("calculate", angleDiff);
|
||||
if (Math.abs(angleDiff) > 90)
|
||||
{
|
||||
angleDiff *= -1;
|
||||
}
|
||||
if (angleDiff < 0)
|
||||
{
|
||||
//console.log("flipr")
|
||||
angle *= -1;
|
||||
}
|
||||
//console.log(angle, dir.x, dir.y, posToCircle.x, posToCircle.y);
|
||||
return new Vector2(dir.x * Math.cos(angle) - dir.y * Math.sin(angle), dir.x * Math.sin(angle) + dir.y * Math.cos(angle));
|
||||
}
|
||||
|
||||
window.addEventListener('resize', function(event) {
|
||||
c.width = window.innerWidth;
|
||||
c.height = window.innerHeight;
|
||||
ctx.translate(c.width / 2, c.height / 2);
|
||||
ctx.scale(1.5, -1.5);
|
||||
Update();
|
||||
}, true);
|
||||
|
||||
function polarCoords(pos)
|
||||
{
|
||||
theta = Math.atan(pos.y / pos.x);
|
||||
if (pos.x < 0)
|
||||
{
|
||||
theta += Math.PI;
|
||||
}
|
||||
if (theta < 0)
|
||||
{
|
||||
theta += Math.PI * 2;
|
||||
}
|
||||
return new Vector2(pos.len, theta * 180 / Math.PI);
|
||||
}
|
||||
|
||||
function redClick()
|
||||
{
|
||||
checkBox = document.getElementById("red");
|
||||
red = checkBox.checked;
|
||||
Clear(ctx);
|
||||
Update();
|
||||
}
|
||||
|
||||
function blueClick()
|
||||
{
|
||||
checkBox = document.getElementById("blue");
|
||||
blue = checkBox.checked;
|
||||
Clear(ctx);
|
||||
Update();
|
||||
}
|
||||
|
||||
Update();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
<p xmlns:cc="http://creativecommons.org/ns#" style="font-size: 1vw; bottom: 0px; position: absolute;">
|
||||
This work is licensed under
|
||||
<a href="http://creativecommons.org/licenses/by-nc-nd/4.0/?ref=chooser-v1" target="_blank" rel="license noopener noreferrer" style="display:inline-block;">CC BY-NC-ND 4.0<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/nc.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/nd.svg?ref=chooser-v1"></a></p>
|
||||
</html>
|
||||
Reference in New Issue
Block a user