Source code of plot #065 back to plot
Download full working sketch as 065.tar.gz.
Unzip, then start a local web server and load the page in a browser.
Unless otherwise noted, code published here is © Gábor L Ugray, shared under the Creative Commons
BY-NC-SA license (Attribution, Non-Commercial, Share-Alike). Files in lib/thirdparty, and additional
libraries in the downloadable archive, are shared under their respective open-source licenses, attributed
to their authors.
import {caption} from "./lib/own/caption.js"
import * as E from "./lib/env.js"
import * as G from "./lib/own/geo.js"
import {SLGen, SLGParams} from "./slgen.js";
import {kdTree} from "../../lib/thirdparty/kdTree.js";
// Declarations below instruct build plugin to copy static files to runtime dir
// STATIC lib/texture.png
const pw = 1480; // Paper width
const ph = 1050; // Paper height
const w = 1480; // Drawing width
const h = 1050; // Drawing height
const margin = 50;
// Random composition
// const time = Math.floor(10 * Math.random() * 100) / 100;
// const a = Math.floor(5 * Math.random() * 100) / 100;
// const b = Math.floor(5 * Math.random() * 100) / 100;
// const c = Math.floor(5 * Math.random() * 100) / 100;
// Reproduce with parameters
// t: 3.67 a: 2.71 b: 2.32 c: 0.84
const time = 3.67;
const a = 2.71;
const b = 2.32;
const c = 0.84;
void setup();
async function setup() {
E.initEnv(w, h, pw, ph);
E.info(`t: ${time} a: ${a} b: ${b} c: ${c}`);
const startTime = performance.now();
await E.spin();
await draw();
const elapsed = performance.now() - startTime;
console.log(`Drawn in ${elapsed} msec`);
}
async function draw() {
const star = u => {
let v = 4 * Math.atan2(u.x, u.y);
v += 4 * Math.abs(Math.sin(v * c * 0.5));
v -= c * 0.5 * Math.abs(Math.sin(v * 1.5));
let val = Math.cos(v + a + u.length() * b);
return val * 0.5 + 0.5;
};
const func = pt => {
const uv = new G.Vec2(pt.x*2/w-1, pt.y*2/h-1);
uv.y *= 0.7;
uv.x *= 2;
if (!uv.isNull()) {
const dot = G.dot2(uv, uv);
const rot = uv.clone().rot(Math.PI * (0.5 + time * 0.2));
uv.x = uv.x / dot + 2.5 * rot.x;
uv.y = -uv.y / dot + 1.5 * rot.y;
uv.setLength(Math.log(uv.length()));
}
return star(uv);
};
const field = pt => {
const val = func(pt);
const dir = new G.Vec2(1, 0).rot(2 * Math.PI * val);
return dir.rot(pt.angle() * .1);
};
const light = pt => 0;
const genParams = new SLGParams();
genParams.bounds = { left: margin, top: margin, right: w - margin, bottom: h - margin};
genParams.seed = new G.Vec2(w * 0.5, h * 0.2);
genParams.step = 1;
genParams.startSep = 8;
genParams.endRatio = 0.15;
genParams.maxLightnessSep = 16;
genParams.minLinePoints = 2 / genParams.step;
await generateStreamlines(genParams, field, light);
}
async function generateStreamlines(genParams, field, luma) {
const drawEveryNLines = 32;
const slGen = new SLGen(genParams, field, luma);
const linesToAdd = [];
while (true) {
const visiblePaths = slGen.genNextLine();
if (!visiblePaths) break;
for (const pts of visiblePaths)
linesToAdd.push(pts);
if (linesToAdd.length >= drawEveryNLines) {
for (const pts of linesToAdd) E.addPath(pts);
linesToAdd.length = 0;
await E.spin();
}
}
for (const pts of linesToAdd) E.addPath(pts);
}