Source code of plot #054 back to plot
Download full working sketch as 054.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} from "./utils/boilerplate.js";
import {mulberry32, setRandomGenerator, rand, rand_range} from "./utils/random.js"
import {SimplexNoise} from "./utils/simplex-noise.js";
import {CanvasMasker} from "./utils/canvas-masker.js";
const pw = 2100; // Paper width
const ph = 1480; // Paper height
const w = 1480; // Drawing width
const h = 1050; // Drawing height
const margin = 50; // Margin (within drawing)
const rf = 1;
const segLen = 2;
let simplex1, simplex2;
let seed = Math.round(Math.random() * 65535);
// seed = 57788;
setSketch(function () {
setRandomGenerator(mulberry32(seed));
simplex1 = new SimplexNoise(rand() * 100);
simplex2 = new SimplexNoise(rand() * 100);
info("Seed: " + seed);
init(w, h, pw, ph);
draw();
});
function draw() {
paper.project.currentStyle.strokeColor = "black";
paper.project.currentStyle.strokeWidth = 2;
const cm = new CanvasMasker(w, h, rf/*, elmCanvasHost*/);
const circles = [];
const nCircles = 20;
const minCircleDist = 100;
const circleSizes = [20, 100];
const curves = [];
const nCurves = 1000;
const curveGap = 10;
const shapeGap = 15;
cm.includeRect(margin, margin, w-2*margin, h-2*margin);
cm.takeSnapshot();
while (circles.length < nCircles) {
const rad = Math.round(rand_range(...circleSizes));
const center = new Point(
Math.round(margin + (w-2*margin) * rand()),
Math.round(margin + (h-2*margin) * rand())
);
let isects = false;
for (const [c2, r2] of circles) {
if (c2.subtract(center).length < r2 + rad + minCircleDist) isects = true;
}
if (isects) continue;
circles.push([center, rad]);
}
const shapePaths = [];
for (const [center, rad] of circles) {
const turnGap = 8;
const pts = makeSpiralPoints(center, rad, turnGap, segLen);
shapePaths.push(pts);
const visiblePaths = cm.getMaskedPoly(pts, true);
for (const pathPts of visiblePaths) {
const path = new paper.Path(pathPts);
paper.project.activeLayer.addChild(path);
}
}
for (const pts of shapePaths)
cm.blockPath(pts, curveGap);
cm.takeSnapshot();
while (curves.length < nCurves) {
const midPt = new Point(
Math.round(margin + (w-2*margin) * rand()),
Math.round(margin + (h-2*margin) * rand())
);
let next = rand() < 0.5
? (pt, dir) => curveGen(pt, dir, simplex1)
: (pt, dir) => curveGen(pt, dir, simplex2);
let pts = cm.genSeq(midPt, next, 100, true);
if (!pts) continue;
curves.push(pts);
cm.blockPath(pts, curveGap);
cm.takeSnapshot();
}
for (const pts of curves) {
const path = new Path({segments: pts});
project.activeLayer.addChild(path);
}
}
function curveGen(pt, dir, simplex) {
const sampleX = ((pt.x / w) - 0.5) * 1;
const sampleY = ((pt.y / h) - 0.5) * 1;
const stepLen = 2;
let angle = Math.PI * simplex.noise2D(sampleX, sampleY);
if (dir < 0) angle += Math.PI;
pt.x += stepLen * Math.sin(angle);
pt.y += stepLen * Math.cos(angle);
return true;
}
function makeSpiralPoints(center, rad, turnGap, segLen) {
const pts = [];
const vec = new Point(0, 0);
const setVec = (angle, r) => {
vec.x = r * Math.sin(angle);
vec.y = r * Math.cos(angle);
}
const startAngle = 2 * Math.PI * rand();
let angle = 0;
let r = turnGap * 0.5;
while (r < rad) {
setVec(angle + startAngle, r);
pts.push(vec.add(center));
const cfer = 2 * r * Math.PI;
const nSteps = Math.max(8, Math.round(cfer / segLen));
angle += 2 * Math.PI / nSteps;
r += turnGap / nSteps;
}
return pts;
}