Source code of plot #053 back to plot
Download full working sketch as 053.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 seed = Math.round(Math.random() * 65535);
//seed = 11454;
setSketch(function () {
setRandomGenerator(mulberry32(seed));
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 = 17;
const minCircleDist = 100;
const circleSizes = [20, 100];
const lines = [];
const nLines = 1500;
const lineAngleQuants = 6;
const lineAnglePlayDeg = 5;
const minLineLength = 10;
const gap = 5;
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]);
}
for (const [center, rad] of circles) {
const pts = makeSpiralPoints(center, rad, 5 + 5 * rand(), segLen);
const visiblePaths = cm.getMaskedPoly(pts, true);
for (const pathPts of visiblePaths) {
const path = new paper.Path(pathPts);
paper.project.activeLayer.addChild(path);
}
}
for (const [center, rad] of circles)
cm.blockCircle(center, rad + gap);
cm.takeSnapshot();
while (lines.length < nLines) {
const midPt = new Point(
Math.round(margin + (w-2*margin) * rand()),
Math.round(margin + (h-2*margin) * rand())
);
let angleDeg = Math.floor(lineAngleQuants * rand()) / lineAngleQuants * 180;
angleDeg += 2 * lineAnglePlayDeg * (rand() - 0.5);
let ab = cm.extendLine(midPt, angleDeg, true);
if (!ab) continue;
ab = shorten(...ab, gap, minLineLength);
if (!ab) continue;
lines.push(ab);
maskLine(cm, ...ab, angleDeg);
cm.takeSnapshot();
}
for (const [a, b] of lines) {
const ln = Path.Line(a, b);
project.activeLayer.addChild(ln);
}
}
function shorten(a, b, gap, minLength) {
const d = b.subtract(a);
const lenAfter = d.length - 2 * gap;
if (lenAfter < minLength) return null;
d.length = gap;
return [a.add(d), b.subtract(d)];
}
function maskLine(cm, a, b, angleDeg) {
const maskThickness = 2;
const up = new Point(-maskThickness, 0).rotate(angleDeg);
const left = up.rotate(-90);
const pts = [
a.add(up).add(left),
a.subtract(up).add(left),
b.subtract(up).subtract(left),
b.add(up).subtract(left),
];
cm.blockPoly(pts);
}
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;
}