IFS with random weight transitions. A+B+C=180 with A!=60 for Wonky. Break the 180 degrees interior angles rule and see what happens.
Log in to post a comment.
// Forked from "Squaring the circle" by matigekunstintelligentie // https://turtletoy.net/turtle/68977787c7 // Forked from "Pythagorean Tree" by matigekunstintelligentie // https://turtletoy.net/turtle/67654b5bd9 const shape = 3; // min=0, max=15, step=1 (Square, Bubble, Blur, Linear, Circle, Sin, Exponential, Swirl, Horseshoe, Polar, Handkerchief, Heart, Disc, Spiral, Diamond, Julia) const x_post = -41; // min=-100, max=100, step=1 const y_post = 30; // min=-100, max=100, step=1 let seed = 666; // min=-1000, max=1000, step=1 const A = 60; // min=-360, max=360, step=1 const B = 70; // min=-360, max=360, step=1 const C = 50; // min=-360, max=360, step=1 // Math.random does not have a seed in JS? function random() { seed = (1664525 * seed + 1013904223) % 4294967296; return (seed >>> 0) / 4294967296; } Canvas.setpenopacity(-0.05); const turtle = new Turtle(); let x = 0; let y = 0; function toRadians(angle) { return angle * (Math.PI/180.); } let cos = (x) => Math.cos(toRadians (x)); let cos2 = (x) => cos(x)*cos(x); let sin = (x) => Math.sin(toRadians (x)); let sin2 = (x) => sin(x)*sin(x); let cossin = (x) => cos(x)*sin(x); let function_set = [[cos2(B), cossin(B), cossin(B), -cos2(B), 0, 0], [cos2(C), -cossin(C), -cossin(C), -cos2(C), sin2(C), cossin(C)], [-cos(A)*cos(C-B), cos(A)*sin(C-B), cos(A)*sin(C-B), cos(A)*cos(C-B), sin2(C), cossin(C)]]; let transition_matrix = Array.from({ length: function_set.length }, () => { let row = Array.from({ length: function_set.length }, () => random()); let sum = row.reduce((acc, val) => acc + val, 0); return row.map(val => val / sum); }); let shapes = ["Square", "Bubble", "Blur", "Linear", "Circle", "Sin", "Exponential", "Swirl", "Horseshoe", "Polar", "Handkerchief", "Heart", "Disc", "Spiral", "Diamond", "Julia"]; let function_transforms = [shapes[shape], "Linear", "Linear", "Linear", "Linear"]; function linear(x,y){ return [x, y]; } function square(x, y){ var r1 = Math.random(); var r2 = Math.random(); return [(r1 - 0.5), (r2 - 0.5)]; } function bubble(x, y){ var r = 1.0; var multiplier = 4.0/(Math.pow(r,2.0) + 4.0); return [multiplier*x, multiplier*y]; } function blur(x, y){ var r1 = Math.random(); var r2 = Math.random(); return [r1*Math.cos(2*Math.PI*r2), r1*Math.sin(2*Math.PI*r2)]; } function circle(x, y){ var t = 2*Math.PI*Math.random(); var u = Math.random() + Math.random(); var r = u; if(u>1.0){ r = 2-u; } return [r*Math.cos(t), r*Math.sin(t)]; } function sin_f(x, y) { return [Math.sin(x), Math.sin(y)]; } function exponential(x, y) { let exp = Math.exp(x - 1); return [exp * Math.cos(Math.PI * y), exp * Math.sin(Math.PI * y)]; } function swirl(x, y) { let r2 = x * x + y * y; return [x * Math.sin(r2) - y * Math.cos(r2), x * Math.cos(r2) + y * Math.sin(r2)]; } function horseshoe(x, y) { let r = Math.sqrt(x * x + y * y); return [(x - y) * (x + y) / r, 2 * x * y / r]; } function polar(x, y) { let r = Math.sqrt(x * x + y * y); let theta = Math.atan2(y, x); return [theta / Math.PI, r - 1]; } function handkerchief(x, y) { let r = Math.sqrt(x * x + y * y); let theta = Math.atan2(y, x); return [r * Math.sin(theta + r), r * Math.cos(theta - r)]; } function heart(x, y) { let r = Math.sqrt(x * x + y * y); let theta = Math.atan2(y, x); return [r * Math.sin(theta * r), -r * Math.cos(theta * r)]; } function disc(x, y) { let r = Math.sqrt(x * x + y * y); let theta = Math.atan2(y, x); return [theta / Math.PI * Math.sin(Math.PI * r), theta / Math.PI * Math.cos(Math.PI * r)]; } function spiral(x, y) { let r = Math.sqrt(x * x + y * y); let theta = Math.atan2(y, x); return [(1 / r) * (Math.cos(theta) + Math.sin(r)), (1 / r) * (Math.sin(theta) - Math.cos(r))]; } function diamond(x, y) { let r = Math.sqrt(x * x + y * y); let theta = Math.atan2(y, x); return [Math.sin(theta) * Math.cos(r), Math.cos(theta) * Math.sin(r)]; } function julia(x, y) { let r = Math.sqrt(x * x + y * y); let theta = Math.atan2(y, x); let omega = Math.random() < 0.5 ? theta / 2 : theta / 2 + Math.PI; return [Math.sqrt(r) * Math.cos(omega), Math.sqrt(r) * Math.sin(omega)]; } let prev = 0; function walk(i) { turtle.jump(x * 100 + x_post, - y * 100 + y_post); turtle.circle(.1); let r = Math.random(); let p_total = 0; for (let j = 0; j < function_set.length; j++) { let f = function_set[j]; p_total += transition_matrix[prev][j]; if (r < p_total) { // Use precomputed function lookup let next; switch (function_transforms[j]) { case "Square": next = square(x, y); break; case "Bubble": next = bubble(x, y); break; case "Blur": next = blur(x, y); break; case "Circle": next = circle(x, y); break; case "Sin": next = sin_f(x, y); break; case "Exponential": next = exponential(x, y); break; case "Swirl": next = swirl(x, y); break; case "Horseshoe": next = horseshoe(x, y); break; case "Polar": next = polar(x, y); break; case "Handkerchief": next = handkerchief(x, y); break; case "Heart": next = heart(x, y); break; case "Disc": next = disc(x, y); break; case "Spiral": next = spiral(x, y); break; case "Diamond": next = diamond(x, y); break; case "Julia": next = julia(x, y); break; default: next = linear(x, y); } // Apply transformation matrix x = next[0] * f[0] + next[1] * f[1] + f[4]; y = next[0] * f[2] + next[1] * f[3] + f[5]; break; } } return i < 1000000; }