Inspiration: vecteezy.com/vector-…-checkerboard-vector
Log in to post a comment.
// You can find the Turtle API reference here: https://turtletoy.net/syntax Canvas.setpenopacity(1); function getRandomInt(max) { return Math.floor(Math.random() * Math.floor(max + 1)); } function rndm(min, max) { return min + getRandomInt(max - min); } // Global code will be evaluated once. const turtle = new Turtle(); var lines = [ new Ray2(new Vec2(rndm(-95, -85), -110), new Vec2(rndm(-15, 25), 220)) ,new Ray2(new Vec2(rndm(-55, -45), -110), new Vec2(rndm(-15, 25), 220)) ,new Ray2(new Vec2(rndm(-15, -5), -110), new Vec2(rndm(-15, 25), 220)) ,new Ray2(new Vec2(rndm(25, 35), -110), new Vec2(rndm(-15, 25), 220)) ,new Ray2(new Vec2(rndm(65, 75), -110), new Vec2(rndm(-15, 25), 220)) ] var circles = [ new Circle(new Vec2(50, -50), rndm(20, 40)) ,new Circle(new Vec2(0, 10), rndm(30, 60)) ,new Circle(new Vec2(30, 70), rndm(30, 60)) ,new Circle(new Vec2(-30, -50), rndm(20, 40)) , new Circle(new Vec2(-80, 40), rndm(20, 30)) ] var penState = 0; function togglePen() { //console.log(penState); if(penState == 0) { turtle.penup(); penState = 1; return; } turtle.pendown(); penState = 0; } // The walk function will be called until it returns false. function walk(i) { var r = new Ray2(new Vec2(-100, (i / 8) - 100), new Vec2(200, 0)); intersections = [r.o]; for(var j = 0; j < lines.length; j++) { var ints = r.getIntersectionRay2(lines[j]); if(ints) { intersections.push(ints.point); } } for(var j = 0; j < circles.length; j++) { var ints = circles[j].getIntersectionsRay2(r); if(ints && ints.length > 1) { intersections.push(ints[0].point); intersections.push(ints[1].point); } } intersections.push(r.o.clone().add(r.d)); intersections.sort(function(a,b) { return a.x - b.x;}) penState = (r.o.y + 110) % 60 > 30? 1: 0; turtle.penup(); for(var j = 0; j < intersections.length; j++) { turtle.goto(intersections[j].simple()); togglePen(); } return i < 1600; } /* All methods by Jurgen, some are commodity, some from Reinder's vec2 functions, some methods implemented to comply with the Vector2 class of the Unity framework */ function Vec2(x, y) {if(typeof y == 'undefined') {this.x = x[0]; this.y = x[1];} else {this.x = x; this.y = y;}} /* returns scalar: length of vector */ Vec2.prototype.length = function() {return Math.sqrt(this.dot(this));} /* returns this after making this' length 1 */ Vec2.prototype.normalize = function() {var l = this.length(); this.x /= l; this.y /= l; return this;} /* returns this after rotating this in radians in clockwise direction for positive rads */ Vec2.prototype.rotate = function(rads) {var x = (Math.cos(rads) * this.x) - (Math.sin(rads) * this.y); var y = (Math.sin(rads) * this.x) + (Math.cos(rads) * this.y); this.x = x; this.y = y; return this;} /* returns Vec2: a copy of this */ Vec2.prototype.clone = function() {return new Vec2(this.x, this.y);} /* returns this after adding parameter Vec2 */ Vec2.prototype.add = function(v) {this.x += v.x; this.y += v.y; return this;} /* returns this after subtracting parameter Vec2 */ Vec2.prototype.subtract = function(v) {this.x -= v.x; this.y -= v.y; return this;} /* returns scalar: dot product of this and parameter Vec2 */ Vec2.prototype.dot = function(v) {return (this.x * v.x) + (this.y * v.y);} /* returns boolean: true if distance(squared) between this and parameter Vec2 v is smaller than optional parameter scalar margin */ Vec2.prototype.equals = function(v, margin = .001) {return this.distanceSquared(v) < margin;} /* returns boolean: true if this and parameter Vec2 are on lines that are parallel to each other within scalar parameter margin */ Vec2.prototype.isParallel = function(v, margin = .001) { var thi = this.clone().normalize().scale(100); var tha = v.clone().normalize().scale(100); return thi.equals(tha, margin) || thi.equals(tha.scale(-1), margin);} /* returns scalar: the squared distance between this an parameter Vec2 */ Vec2.prototype.distanceSquared = function(v) {return Math.pow(this.x - v.x, 2) + Math.pow(this.y - v.y, 2);} /* returns scalar: the distance between this an parameter Vec2 */ Vec2.prototype.distance = function(v) {return Math.sqrt(this.distanceSquared(v));} /* returns scalar: the angle in radians between this and parameter Vec2 */ Vec2.prototype.angle = function(v) {return Math.acos( this.dot(v) / (this.length() * v.length()) );} /* returns Vec2: interpolated linearly between parameter t = 0 (this) and t = 1 (paramter Vec2) (e.g. t = .5 gives a Vec2 with minimum and equal distance to this and parameter Vec2 */ Vec2.prototype.lerp = function(v, t) {if(t < 0 || 1 < t) { throw new Error('Parameter t out of bounds for Vec2.lerp(v, t)'); } var dx = v.x - this.x; var dy = v.y - this.y; this.x += t * dx; this.y += t * dy; return this;} /* returns Vec2: alias of lerp() */ Vec2.prototype.interpolateLinearly = function(v, t) {return this.lerp(v, t);} /* returns this after multiplying itself with scalar parameter */ Vec2.prototype.scale = function(s) {this.x *= s; this.y *= s; return this;} /* returns array[2]: an array representation of this as [x, y] */ Vec2.prototype.simple = function() {return [this.x, this.y];} /* returns this after making this the length of parameter length */ Vec2.prototype.scaleAbsolute = function(length) {return this.scale(length / this.length());} /* returns this: alias of scale() */ Vec2.prototype.scaleRelative = function(s) {return this.scale(s);} /* returns Vec2: a vector of same magnitude as this, perpendicular to this. The result is always rotated 90-degrees in a counter-clockwise direction for a 2D coordinate system where the positive Y axis goes up. */ Vec2.prototype.getPerpendicular = function() {return new Vec2(-this.y, this.x);} /* returns Vec2: a vector reflected by a surface perpendicular to parameter norm as if the surface is a perfect mirror */ Vec2.prototype.reflect = function(norm) {var n = norm.clone().normalize(); return this.clone().subtract( n.scale(2 * this.dot(n)) ).scale(-1);} /* return scalar: the Z-component of the resulting 3D Vector would this and parameter Vec2 be in the 3D plane x = 0, y = 0 */ Vec2.prototype.cross = function(v) {return (this.x * v.y) - (this.y * v.x);} /* All methods by Jurgen, some are commodity, some methods implemented to comply with the Ray2D class of the Unity framework */ function Ray2(originVec2, directionVec2) { this.o = originVec2; this.d = directionVec2; } /* returns Ray2: a copy of this */ Ray2.prototype.clone = function() { return new Ray2(this.o.clone(), this.d.clone()); } /* returns this: draws this ray (from t = 0 to t = 1) on parameter turtle t */ Ray2.prototype.draw = function(t) { t.jump(this.o.x, this.o.y); t.goto(this.o.x + this.d.x, this.o.y + this.d.y); return this; } /* returns this: draws this ray (from t = 0 to t = 1) on parameter turtle t with an arrow head of size parameter ratio */ Ray2.prototype.drawArrow = function(t, arrawHeadRatio=.3) { this.draw(t); var newO = this.o.clone().add(this.d); var c1 = this.d.clone().scale(-1); var c2 = c1.clone().rotate(Math.PI / 4).scale(arrawHeadRatio); c1.rotate(Math.PI / -4).scale(arrawHeadRatio); new Ray2(newO, c1).draw(t); new Ray2(newO, c2).draw(t); return this; } /* returns Vec2: alias for getPointAbsolute */ Ray2.prototype.getPoint = function(distance) { return this.getPointAbsolute(distance); } /* returns Vec2: A point on this ray when the direction is resized to length parameter distance */ Ray2.prototype.getPointAbsolute = function(distance) { return this.o.clone().add(this.d.clone().scaleAbsolute( distance )); } /* returns Vec2: A point on this ray when the direction is multiplied by parameter t */ Ray2.prototype.getPointRelative = function(t) { return this.o.clone().add(this.d.clone().scale(t)); } /* returns intersectioninfo or false: object with a point (Vec2) of intersection and a t1 and t2 representing the the scalar to apply to resp this' direction or parameter r's direction to get to that point */ Ray2.prototype.getIntersectionRay2 = function (r) { var deltaO = this.o.clone().subtract(r.o); var perp = this.d.getPerpendicular(); var det = r.d.dot(perp); if(det == 0) { return false; } var t1 = r.d.cross(deltaO) / det; var t2 = deltaO.dot(perp) / det; return { point: this.getPointRelative(t1), t1: t1, t2: t2 } } /* All methods by Jurgen */ function Circle(centerVector, radius) { this.o = centerVector; this.r = radius; } /* returns this: draws this circle on parameter turtle t */ Circle.prototype.draw = function(t) { var h = t.heading(); t.setheading(0); t.jump(this.o.x, this.o.y - this.r); t.circle(this.r); t.setheading(h); return this; } /* returns intersectioninfo or false: array of objects where each item has a point (Vec2) of intersection and a t representing the the scalar to apply parameter r's direction to get to that point */ Circle.prototype.getIntersectionsRay2 = function(r) { var intersections = []; var OM = r.o.clone().subtract(this.o); var A = Math.pow( r.d.length(), 2 ); var B = 2 * r.d.dot( OM ); var C = Math.pow(OM.length(), 2) - Math.pow(this.r, 2); var Q = (B*B) - (4*A*C); var G = 1 / (2*A); var QQ = G*Math.sqrt(Q); var BB = (-1 * B * G); if(Q > 0) { intersections.push(BB + QQ); intersections.push(BB - QQ); } else if (Q == 0){ intersections.push(BB - QQ); } else { return false; } intersections.sort(function(a,b) { return a - b;}); for(var i = 0; i < intersections.length; i++) { intersections[i] = { point: r.getPointRelative(intersections[i]), t: intersections[i]}; } return intersections; }