### Coronavirus COVID SARS-CoV-2

Ray marching with both spherical and cartesian repetition

```// Forked from "Deep ocean floor" by PavlikEnemy
// https://turtletoy.net/turtle/4bbcc9c6b4

// Forked from "Making waves" by PavlikEnemy
// https://turtletoy.net/turtle/13016b43d5

Canvas.setpenopacity(0.3);

const t = new Turtle();

const scrZ = 2.0;
const scrRx = 1.0;
const scrRy = 1.0;

const eyeZ = 4.0;

const camRotX = 0;
const camRotY = 0;

const step = 0.25;

const Dmax = scrZ + 10;
const INF = Dmax * 2;

const EPS = 0.0001;

const MAX_N_STEPS = 64;

function plus3(v1, v2) {
return [v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2]];
}

function minus3(v1, v2) {
return [v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2]];
}

function mod3(v1, v2) {
return [v1[0] % v2[0], v1[1] % v2[1], v1[2] % v2[2]];
}

function multiply3(a, v) {
return [a * v[0], a * v[1], a * v[2]];
}

function abs3(v) {
return [Math.abs(v[0]), Math.abs(v[1]), Math.abs(v[2])];
}

function length3(v) {
return Math.sqrt(v[0]**2 + v[1]**2 + v[2]**2);
}

function normalize3(v) {
return multiply3(1 / length3(v), v);
}

function rotate2(v, phi) {
return [v[0] * Math.cos(phi) - v[1] * Math.sin(phi),
v[0] * Math.sin(phi) + v[1] * Math.cos(phi)];
}

function cast_ray_from_screen(x, y) {
let px = -scrRx + 2 * scrRx * (x / 200);
let py = -scrRy + 2 * scrRy * (y / 200);
let pz = scrZ;

[px, py] = rotate2([px, py], camRotY);
[py, pz] = rotate2([py, pz], camRotX);

let ex = 0, ey = 0, ez = eyeZ;

//[ex, ey] = rotate2([ex, ey], camRotY)
[ey, ez] = rotate2([ey, ez], camRotX)

let p = [px, py, pz];
let eye = [ex, ey, ez];

let dir = normalize3(minus3(p, eye));

return [p, dir];
}

function intersect_df(p, dir, df) {
let D = 0;
var n_steps;

for (n_steps = 0; n_steps < MAX_N_STEPS; n_steps++) {
let d = scene_df(p);

if ((d < EPS) || (D > Dmax)) {
break;
}
else {
p = plus3(p, multiply3(d, dir));

D += d;
}
}

return [p, D, n_steps];
}

function cylinder_z_df(p, c, h, r) { // axis z
const [px, py, pz] = minus3(p, c);

let dxy = Math.sqrt(px**2 + py**2) - r;
let dz = Math.abs(pz) - h/2;

if (dxy > 0) {
if (dz > 0) {
return Math.sqrt(dxy**2 + dz**2);
}
else {
return dxy;
}
}
else {
if (dz > 0) {
return dz;
}
else {
return Math.max(dxy, dz);
}
}
}

function cylinder_x_df(p, c, h, r) {
const [px, py, pz] = minus3(p, c);

let dyz = Math.sqrt(py**2 + pz**2) - r;
let dx = Math.abs(px) - h/2;

if (dyz > 0) {
if (dx > 0) {
return Math.sqrt(dyz**2 + dx**2);
}
else {
return dyz;
}
}
else {
if (dx > 0) {
return dx;
}
else {
return Math.max(dyz, dx);
}
}
}

function plane_df(p) { // z = 0
return p[2];
}

function sphere_df(p, c, r) {
return length3(minus3(c, p)) - r;
}

function smooth_min(a, b, k) { // see https://iquilezles.org/articles/smin/
let h = Math.max(k - Math.abs(a - b), 0) / k;
return Math.min(a, b) - h*h*h*k*(1/6);
}

function smooth_max(a, b, k=1) {
return -smooth_min(-a, -b, k);
}

function cartesian2spherical(p) {
let rho = length3(p);
let theta = Math.asin(p[1] / rho);
let phi = Math.atan2(p[2], p[0]);

return [rho, theta, phi];
}

function spherical2cartesian(rho, theta, phi) {
return [rho * Math.cos(theta) * Math.cos(phi),
rho * Math.sin(theta),
rho * Math.cos(theta) * Math.sin(phi)];
}

function scene_df(p) {
let p0 = p;

// infinite repetition

const periods = [4.0, 4.0, 4.0];
const half_periods = multiply3(0.5, periods);

if (length3(p) > 1.5) {
p = abs3(p);

p = minus3(mod3(plus3(p, half_periods), periods), half_periods);
}

// spherical repetition with extra shift

let [rho, theta, phi] = cartesian2spherical(p);

phi += 20 * Math.PI/180;

let per_theta = Math.PI / 13;
let per_phi = Math.PI / 12;

let t_th = Math.floor((Math.abs(theta) + per_theta/2) / per_theta);
let t_ph = Math.floor((Math.abs(phi) + per_phi/2) / per_phi);

if (t_th <= 6) {
if (t_th > 0) {
theta = (Math.abs(theta) + per_theta/2) % per_theta - per_theta/2;
}

if (t_ph > 0) {
phi = (Math.abs(phi) + t_th * per_phi/2 + per_phi/2) % per_phi - per_phi/2;
}

p = spherical2cartesian(rho, theta, phi);
}

const R = 1.0;
const r = 0.03;
const h = 12 * r;

let df = cylinder_x_df(p, [R, 0, 0], h, r);

for (let i = 0; i < 3; i++) {
let psi = (t_th * 19 + t_ph * 17) * Math.PI / 6 + 2 * Math.PI / 3 * i;
let c = [R + h/2 + r/2, r * Math.cos(psi), r * Math.sin(psi)];

let s_df = sphere_df(p, c, r)

df = smooth_min(df, s_df, 0.05);
}

let sph_df = sphere_df(p, [0, 0, 0], R);

let noise = 0.02 * Math.sin(30 * p0[0]) * Math.sin(30 * p0[1]) * Math.sin(30 * p0[2]);

sph_df += noise;

df += 0.5 * noise;

df = smooth_min(sph_df, df, 0.2);

return df;
}

let x = 0;
let y = 0;

function walk(frame) {
const [p, dir] = cast_ray_from_screen(x, y);

const [p_int, dist_to_int, n_steps] = intersect_df(p, dir, scene_df);

if (dist_to_int < Dmax) {
//let s = step * Math.max(0.1, (1 - n_steps / 50));
let s = step * Math.max(0.1, (1 - n_steps / 50))**2.5;

t.seth(360 * Math.random());

for (let i = 0; i < 4; i++) {
t.jump(x - 100, y - 100);
t.right(90);
t.forward(s);
}
}

x += step;
if (x > 200) {
y += step;
x = 0;
}

return (y < 200);
}```