function rosetteSegments(n, d, min = 0, max = 100) {
const delta = (Math.PI * 2) / n;
const polar = (ang) => [Math.cos(ang), Math.sin(ang)];
const origins = [];
const rays = [];
for (let i = 0; i < n; i++) {
const a = polar(delta * i);
origins[i] = a;
const b = polar(delta * (i + d));
const c = polar(delta * (i - d));
rays[i] = [vec2.sub([], b, a), vec2.sub([], c, a)];
}
let t = [];
for (let i = 0; i < n; i++) {
let p = origins[i];
t.push([]);
for (let k of [0, 1]) {
let v = rays[i][k];
t[i][k] = [1];
for (let j = 0; j < n; j++) {
if (j == i) continue;
let P = origins[j];
for (let V of rays[j]) {
let den = v[0] * V[1] - v[1] * V[0];
if (Math.abs(den) <= 0.0001) continue;
let u = (V[1] * (P[0] - p[0]) + p[1] * V[0] - P[1] * V[0]) / den;
if (u > Number.EPSILON && u < 1 - Number.EPSILON) t[i][k].push(u);
}
}
}
}
let edges = [];
for (let i = 0; i < n; i++) {
let p = origins[i];
for (let k of [0, 1]) {
let v = rays[i][k];
t[i][k].sort((a, b) => a - b);
let prev = p;
let count = 0;
for (let u of t[i][k]) {
let q = vec2.scaleAndAdd([], p, v, u);
if (!samePoint(prev, q)) {
if (count >= max) break;
if (count >= min) edges.push([prev, q]);
count++;
}
prev = q;
}
}
}
return edges;
}