Random walks on cube (with rotations)
Log in to post a comment.
const seed = 1100; // min=1, max=2000, step=1 const N = 250; // min=10, max=1000, step=1 const min_step = 0.005; const phi_x = -35.0; // min=-180.0, max=180.0, step=0.1 const phi_y = 35.0; // min=-180.0, max=180.0, step=0.1 const phi_z = 25.0; // min=-180.0, max=180.0, step=0.1 Canvas.setpenopacity(-1); const dash = 2.0; const t = new Turtle(); const verts = [[-1, -1, -1], [-1, -1, +1], [-1, +1, +1], [-1, +1, -1], [+1, -1, -1], [+1, -1, +1], [+1, +1, +1], [+1, +1, -1]]; const edges = [[0, 1], [1, 2], [2, 3], [3, 0], [4, 5], [5, 6], [6, 7], [7, 4], [0, 4], [1, 5], [2, 6], [3, 7]]; const faces = [[3, 0, 1, 2], [4, 7, 6, 5], [1, 0, 4, 5], [2, 1, 5, 6], [3, 2, 6, 7], [0, 3, 7, 4]]; let cur_rand = seed; function rand() { cur_rand = (cur_rand * 48271) % (2**31 - 1); return cur_rand; } function rand_float() { return rand() / (2**31 - 1); } function rand_bool() { return (rand() % 2 == 0); } function deg2rad(x) { return x / 180.0 * Math.PI} function plus(v1, v2) { return [v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2]]; } function minus(v1, v2) { return [v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2]]; } function mul(v, scale) { return [v[0] * scale, v[1] * scale, v[2] * scale] } function len(v) { return Math.sqrt(v[0]**2 + v[1]**2); } function cross(v1, v2) { return [v1[1] * v2[2] - v1[2] * v2[1], v1[2] * v2[0] - v1[0] * v2[2], v1[0] * v2[1] - v1[1] * v2[0]]; } function rotate(v, phi) { return [v[0] * Math.cos(phi) + v[1] * Math.sin(phi), -v[0] * Math.sin(phi) + v[1] * Math.cos(phi)]; } function draw_cube(dx, dy, dz, scale, phi_x, phi_y, phi_z) { let v = []; for (let i = 0; i < verts.length; i++) { let vi = verts[i]; let [x, y, z] = vi; [x, y, z] = mul([x, y, z], scale); [y, z] = rotate([y, z], phi_x); [x, z] = rotate([x, z], phi_y); [x, y] = rotate([x, y], phi_z); [x, y, z] = plus([x, y, z], [dx, dy, dz]); v[i] = [x, y, z]; } let f_invisible = []; let v_invisible = []; for (let i = 0; i < verts.length; i++) { v_invisible[i] = true; } for (let i = 0; i < faces.length; i++) { let f = faces[i]; let v1 = v[f[0]], v2 = v[f[1]], v3 = v[f[2]], v4 = v[f[3]]; let v12 = minus(v2, v1), v13 = minus(v3, v1); let n = cross(v12, v13); f_invisible[i] = (n[2] < 0); for (let j = 0; j < f.length; j++) { v_invisible[f[j]] &&= f_invisible[i]; } } let e_invisible = []; for (let i = 0; i < edges.length; i++) { let e = edges[i]; e_invisible[i] = v_invisible[e[0]] || v_invisible[e[1]] } for (let i = 0; i < edges.length; i++) { let e = edges[i]; let v1 = v[e[0]], v2 = v[e[1]]; if (e_invisible[i]) { if (! v_invisible[e[0]]) { [v1, v2] = [v2, v1] } let v12 = minus(v2, v1) let L = len(v12) let dx = v12[0] / L * dash, dy = v12[1] / L * dash for (let x = v1[0], y = v1[1], cL = 0; cL <= L - dash; cL += 2 * dash, x += 2 * dx, y += 2 * dy) { t.jump(x, y) t.goto(x + dx, y + dy) } } else { t.jump(v1[0], v1[1]) t.goto(v2[0], v2[1]) } } let traj = []; traj[0] = [0, rand_float(), rand_float()]; let prev_dir = rand() % 4; // 0 -- left, 1 -- up, 2 -- right, 3 -- down const stepx = [-1, 0, 1, 0]; const stepy = [0, -1, 0, 1]; for (let i = 1; i <= N; i++) { let new_dir = rand_bool() ? ((prev_dir + 1) % 4) : ((prev_dir + 3) % 4); //let new_step = min_step + (max_step - min_step) * rand_float(); let maxs = (new_dir == 0) ? traj[i - 1][1] : ((new_dir == 1) ? (traj[i - 1][2]) : ((new_dir == 2) ? (1 - traj[i - 1][1]) : (1 - traj[i - 1][2]))) let new_step = min_step + rand_float() * (maxs - min_step); traj[i] = [0, traj[i - 1][1] + stepx[new_dir] * new_step, traj[i - 1][2] + stepy[new_dir] * new_step]; prev_dir = new_dir; } const gap = 0.02; let segm = []; segm.push([[traj[0][1], traj[0][2]], [traj[1][1], traj[1][2]]]); for (let i = 2; i <= N; i++) { let p1x = traj[i - 1][1], p1y = traj[i - 1][2]; let p2x = traj[i][1], p2y = traj[i][2]; if (p1x == p2x) { let px = p1x; [p1y, p2y] = [Math.min(p1y, p2y), Math.max(p1y, p2y)]; let y = []; for (let s of segm) { if (s[0][1] == s[1][1]) { let sy = s[0][1]; let sx1 = Math.min(s[0][0], s[1][0]), sx2 = Math.max(s[0][0], s[1][0]); if ((sx1 < px) && (px < sx2) && (p1y < sy) && (sy < p2y)) { y.push(sy) } } } if (y.length > 0) { y.sort((a, b) => a - b); if (p1y < y[0] - gap) { segm.push([[px, p1y], [px, y[0] - gap]]) } for (let j = 1; j < y.length; j++) { if (y[j - 1] + gap < y[j] - gap) { segm.push([[px, y[j - 1] + gap], [px, y[j] - gap]]) } } if (y[y.length - 1] + gap < p2y) { segm.push([[px, y[y.length - 1] + gap], [px, p2y]]) } } else { segm.push([[px, p1y], [px, p2y]]) } } else { let py = p1y; [p1x, p2x] = [Math.min(p1x, p2x), Math.max(p1x, p2x)]; let x = []; for (let s of segm) { if (s[0][0] == s[1][0]) { let sx = s[0][0]; let sy1 = Math.min(s[0][1], s[1][1]), sy2 = Math.max(s[0][1], s[1][1]); if ((sy1 < py) && (py < sy2) && (p1x < sx) && (sx < p2x)) { x.push(sx) } } } if (x.length > 0) { x.sort((a, b) => a - b); if (p1x < x[0] - gap) { segm.push([[p1x, py], [x[0] - gap, py]]) } for (let j = 1; j < x.length; j++) { if (x[j - 1] + gap < x[j] - gap) { segm.push([[x[j - 1] + gap, py], [x[j] - gap, py]]) } } if (x[x.length - 1] + gap < p2x) { segm.push([[x[x.length - 1] + gap, py], [p2x, py]]) } } else { segm.push([[p1x, py], [p2x, py]]) } } } for (let i = 0; i < faces.length; i++) { if (! f_invisible[i]) { let i1 = faces[i][0], i2 = faces[i][1], i3 = faces[i][3] let x0 = v[i1][0], y0 = v[i1][1]; let ax = v[i2][0] - v[i1][0], ay = v[i2][1] - v[i1][1]; let bx = v[i3][0] - v[i1][0], by = v[i3][1] - v[i1][1]; for (let s of segm) { t.jump(x0 + s[0][0] * ax + s[0][1] * bx, y0 + s[0][0] * ay + s[0][1] * by); t.goto(x0 + s[1][0] * ax + s[1][1] * bx, y0 + s[1][0] * ay + s[1][1] * by); } } } } draw_cube(0, 0, 0, 55, deg2rad(phi_x), deg2rad(phi_y), deg2rad(phi_z))