Source code of plot #057 back to plot
Download full working sketch as 057.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.
///<reference path="../pub/lib/paper.d.ts" />
import {info, init, loadLib, setSketch, spin, dbgRedraw} from "./utils/boilerplate.js";
import {mulberry32, setRandomGenerator, rand} from "./utils/random.js"
import {SimplexNoise} from "./utils/simplex-noise.js";
import {kdTree} from "./utils/kdTree.js";
const pw = 2100; // Paper width
const ph = 1480; // Paper height
const w = 2100; // Drawing width
const h = 1480; // Drawing height
let simplex1, simplex2;
let seed = Math.round(Math.random() * 65535);
setSketch(async function () {
setRandomGenerator(mulberry32(seed));
simplex1 = new SimplexNoise(rand() * 100);
simplex2 = new SimplexNoise(rand() * 100);
info("Seed: " + seed);
init(w, h, pw, ph);
const startTime = performance.now();
await draw();
const elapsed = performance.now() - startTime;
console.log(`Drawn in ${elapsed} msec`);
});
async function draw() {
paper.project.currentStyle.strokeColor = "black";
paper.project.currentStyle.strokeWidth = 2;
const kdt1 = new kdTree([], (a, b) => Math.sqrt((a.x-b.x)**2 + (a.y-b.y)**2), ["x", "y"]);
const kdt2 = new kdTree([], (a, b) => Math.sqrt((a.x-b.x)**2 + (a.y-b.y)**2), ["x", "y"]);
const originW = 1480;
const originH = 1050;
const curves = [];
const nCurves = 1200;
const startMinGap = 10.1;
const endMinGap = 5;
const minLen = 20;
const maxLen = 200;
while (curves.length < nCurves) {
let startPt = getRandomPoint(originW, originH);
while (true) {
if (kdt1.nearest(startPt, 1, startMinGap) + kdt2.nearest(startPt, 1, startMinGap) == 0)
break;
startPt = getRandomPoint(originW, originH);
}
const curveSet = rand() < 0.5 ? 0 : 1;
const kdt = curveSet == 0 ? kdt1 : kdt2;
let [pts, len] = genCurve(startPt, curveSet, kdt1, kdt2, endMinGap, maxLen);
if (len < minLen) continue;
const path = addPath(pts);
curves.push({pts, path});
for (const pt of pts)
kdt.insert(pt);
if ((curves.length%10) == 0) await spin();
}
await spin();
const nCurvesPruned = Math.round(nCurves * 0.6);
while (curves.length > nCurvesPruned) {
const ix = Math.floor(curves.length * rand());
const c = curves[ix];
const midPt = c.pts[Math.round(c.pts.length/2)];
let dn = getNormDist(midPt);
dn = Math.pow(dn, 4);
const thresh = rand();
if (thresh > dn)
continue;
curves.splice(ix, 1);
c.path.remove();
}
dbgRedraw();
for (const pts of curves) addPath(pts);
await spin();
}
function getNormDist(pt) {
const dist = Math.sqrt((pt.x-w/2)**2 + (pt.y-h/2)**2);
return dist / w;
}
function addPath(pts) {
const path = new Path({segments: pts});
project.activeLayer.addChild(path);
return path;
}
function getRandomPoint(originW, originH) {
return new Point(
Math.round(w * 0.5 + (rand() - 0.5) * originW),
Math.round(h * 0.5 + (rand() - 0.5) * originH));
}
function genCurve(startPt, curveSet, kdt1, kdt2, endMinGap, maxLen) {
const kdtMine = curveSet == 0 ? kdt1 : kdt2;
const kdtOther = curveSet == 0 ? kdt2 : kdt1;
const noise = curveSet == 0 ? simplex1 : simplex2;
const stepLen = 2;
const res = [startPt.clone()];
let len = 0;
for (let pt = next(res[0], 1); ; pt = next(pt, 1)) {
if (kdtMine.nearest(pt, 1, endMinGap) != 0) break;
if (kdtOther.nearest(pt, 1, stepLen) != 0) break;
if (len > maxLen) break;
res.push(pt);
len += stepLen;
if (res.length == 2) res[0].tan = pt.tan;
}
for (let pt = next(res[0], -1); ; pt = next(pt, -1)) {
if (kdtMine.nearest(pt, 1, endMinGap) != 0) break;
if (kdtOther.nearest(pt, 1, stepLen) != 0) break;
if (len > maxLen) break;
res.unshift(pt);
len += stepLen;
}
return [res, len];
function next(pt, dir) {
const sampleX = ((pt.x / w) - 0.5) * 0.8 + 2;
const sampleY = ((pt.y / h) - 0.5) * 0.8 + 2;
let angle = Math.PI * noise.noise2D(sampleX, sampleY);
if (dir < 0) angle += Math.PI;
const res = new Point(
pt.x + stepLen * Math.sin(angle),
pt.y + stepLen * Math.cos(angle));
res.tan = angle;
return res;
}
}