https://highlight.xyz/mint/64eec29adb2d22cad96e3151
The basis of Triage is Delaunay triangulation (DT) from the d3-delaunay library which is based on the Delaunator by Volodymyr Agafonkin. It is a “technique for creating a mesh of contiguous, nonoverlapping triangles from a dataset of points.”

The algorithm is based on ideas from the following papers:
A simple sweep-line Delaunay triangulation algorithm, 2013, Liu Yonghe, Feng Jinming and Shao Yuehong
S-hull: a fast radial sweep-hull routine for Delaunay triangulation, 2010, David Sinclair
A faster circle-sweep Delaunay triangulation algorithm, 2011, Ahmad Biniaz and Gholamhossein Dastghaibyfard


The first step of drawing an iteration of Triage is the creation of a small random vector path in the center of the canvas containing about twenty segments. Then, the center of the shape is moved to the center of the canvas using geometric.js.
In order to fill the canvas efficiently, an optimal rotation for the shape must be found. A bounding box will be used to compare the shape W x L ratio to the canvas ratio. By rotating the shape and its bounding box 360 degrees in 30 degree increments and recording the ratio for each turn, a sample of 12 possible rotations with corresponding ratios can be used to find the optimal rotation.

The array of points is given to the function geometric.polygonScaleArea() which scales up the shape from the center until the edge of the canvas is detected. The next step loops through the paths of the shape to create Bezier paths using the bezier.js function new Bezier(p1.x,p1.y,p2.x,p2.y,p3.x,p3.y,p4.x,p4.y). The second part of the loop “generates a curve’s outline at distance d along the curve normal and anti-normal. The result is an array of curves that taken together form the outline path for this curve.”
https://pomax.github.io/bezierjs/
for(b=3;b<rotPoly_s.length;b+=3){
//generate curve
const bcurve = new Bezier(
rotPoly_s[b][0], rotPoly_s[b][1],
rotPoly_s[b-1][0], rotPoly_s[b-1][1],
rotPoly_s[b-2][0], rotPoly_s[b-2][1],
rotPoly_s[b-3][0], rotPoly_s[b-3][1]);
//curve outlines
or=hl.random(lo,hi)
om=hl.random(1.2,1.3)
for(var toffo=0; toffo<=1; toffo+=0.4) {
var doc = c => drawCurve(c);
var outline = bcurve.outline(or);
outline.curves.forEach(doc);
or=or*om
}
}

Another great thing about bezier.js is the ability to “generate a LookUp Table of coordinates on the curve, spaced at parametrically equidistance intervals.” Inside the drawCurve function, the LUTs are found for each curve and stored to be used for the triangle mesh input.
function drawCurve(curve, offset){
...
var LUT = zcurve.getLUT(LUTsteps);
LUT.forEach(p => dlc.push([p.x,p.y]));
}

The triangle mesh is generated by d3.js, then the resulting points are sorted into groups of three so that each triangle can be edited individually.
let verts = newVerts
voronoi = d3.voronoi();
let triangles = voronoi(verts).triangles();
triangles.map(t => t.map(v => tris.push([v[0], v[1]])))
count=0
t=[]
for(t=0;t<tris.length;t++){
if(count==3){
t.push([
tris[t-3][0], tris[t-3][1],
tris[t-2][0], tris[t-2][1],
tris[t-1][0], tris[t-1][1]
])
count=0
}
count++
}
Some filters are used to cull triangles that have at least one angle of less than 4 degrees, triangles that get too close to the canvas edge, and triangles that are over a certain size. Each triangle is then scaled down slightly (to create small gaps) and filled with hatch lines. Noise is mapped to the stroke weight, number of hatch lines, and angle of hatch lines to create interesting patterns in the texture of the mesh.
That’s about it, thank you for reading this far.

//the end

