// You can find the Turtle API reference here: https://turtletoy.net/syntax
Canvas.setpenopacity(.7);
const grid = 5;
const radius = 15;
// Global code will be evaluated once.
const turtle = new Turtle();
var size = 200 / grid;
// The walk function will be called until it returns false.
function walk(i) {
var l1 = getRandomPoint(1);
var l2 = getRandomPoint(-1);
var intersections = [];
//var O = [0, 0];
for(var j = 0; j < grid * grid; j++) {
var x = j % grid;
var y = j / grid | 0;
var M = [((x + .5) * size) - 100, ((y + .5) * size) - 100];
var D = [l2[0] - l1[0], l2[1] - l1[1]];
var O = l1;
// If you are in 2D vector form the equations above can be represented as vectors by using
// origin O and direction of a ray D, where |D| must be strongly positive for the ray to
// intersect the circle. Let's say that the circle center is at position vector M and its
// radius is R. First, you need to define the vector from the center of the circle being M
// to the ray origin O:
//
// OM = O - M (O and M are position vectors)
var OM = [O[0] - M[0], O[1] - M[1]];
// In vector form you can define the quadratic equation coefficients like follows ( ^ means
// to the power of, dot means dot product between two 2D vectors, |VECTOR| means length of
// vector ):
//
// A = |D|^2
var A = vecLength(D) * vecLength(D);
// B = 2 * D dot OM
var B = 2 * dot2d(D, OM);
// C = |OM|^2 - R^2
var C = (vecLength(OM) * vecLength(OM)) - (radius * radius)
// Now we can calculate the discriminant: Q = B^2 - 4*A*C
var Q = (B*B) - (4*A*C);
if(Q > 0) {
// If the given value is negative, there is no intersection if the value is zero, you have
// one root and one intersection as two roots for two intersection points. Store the value
// of G = 1/(2*A) in a variable it will become in handy later. Now calculate the determinant
// Q = G*sqrt(Q) and update the value of B = (-B * G)
var G = 1 / (2*A);
Q = G*Math.sqrt(Q);
B = (-1 * B * G);
// Now we are ready to calculate the intersection points. Let's call them P1 and P2 where we
// will have an equation as follows where B and Q are number scalars:
// P1 = D * (B + Q) + O
//var p1 = [(D[0] * (B + Q)) + O[0], (D[1] * (B + Q)) + O[1]];
//var p1 = addVec(multiplyVec(D, B+Q), O);
intersections.push(B+Q);
// P2 = D * (B - Q) + O
//var p2 = [(D[0] * (B - Q)) + O[0], (D[1] * (B - Q)) + O[1]];
//var p2 = addVec(multiplyVec(D, B-Q), O);
intersections.push(B-Q);
// The closest intersection point to the ray origin is P2 and the distant one is P1
//line(l1, p2);
//line(p1, l2);
} else {
//line(l1, l2);
}
}
var points = [l1];
intersections.sort(function(a,b) { return a - b;});
for(var j = 0; j < intersections.length; j++) {
points.push(addVec(multiplyVec(D, intersections[j]), O));
}
points.push(l2);
for(var j = 0; j < points.length; j = j + 2) {
line(points[j], points[j + 1]);
}
return i < 200;
}
function getRandomPoint(side) {
//var pt = 400 * Math.sin(Math.random() * Math.PI * 2);
var pt = 400 * Math.sin(Math.random() * Math.PI);
if(pt < 200) {
return side < 0? [pt - 100, -100]: [-100, pt - 100]; //top: left
}
return side < 0? [100, pt - 300]: [pt - 300, 100]; //right: bottom
}
const line = (p1, p2) => {
turtle.jump(p1[0], p1[1]);
turtle.goto(p2[0], p2[1]);
}
function dot2d(v1, v2) {
return (v1[0] * v2[0]) + (v1[1] * v2[1]);
}
function vecLength(v) {
return Math.sqrt((v[0] * v[0]) + (v[1] * v[1]));
}
function multiplyVec(vec, multiplier) {
return [vec[0] * multiplier, vec[1] * multiplier];
}
function addVec(vec1, vec2) {
return [vec1[0] + vec2[0], vec1[1] + vec2[1]];
}