gosper_tray = () => {
const {
primitives: P,
extrusions: E,
transforms: T,
booleans: B,
maths: M
} = jscad;
const { TAU } = M.constants;
const SQRT7 = Math.sqrt(7);
const FACTOR = 1 / SQRT7;
const ANGLE = -Math.acos(5 / (2 * SQRT7));
const iter = function* (obj, fn, nb) {
yield obj;
for (let i = 1, o = obj; i < nb; i++) yield (o = fn(o));
};
const SIZE = 100;
const recurs = (obj) => {
const g = T.scale([FACTOR, FACTOR, 1], obj);
const tg = T.translate([0, 2 * SIZE * FACTOR * Math.cos(TAU / 12), 0], g);
const gg = B.union([g, ...iter(tg, (obj) => T.rotateZ(TAU / 6, obj), 6)]);
return T.translateZ(LAYER_HEIGHT, T.rotateZ(ANGLE, gg));
};
const hex = (r) => {
const rotate = (v) => M.vec2.rotate([], v, [0, 0], TAU / 6);
return P.polygon({ points: [...iter([r, 0], rotate, 6)] });
};
const NB = 7;
const LAYER_HEIGHT = 5;
const layer0 = E.extrudeLinear({ height: LAYER_HEIGHT }, hex(SIZE));
const holeBase = T.rotateZ(ANGLE - TAU / 12, hex(2 * SIZE * FACTOR));
const hole = E.extrudeLinear({ height: NB * LAYER_HEIGHT }, holeBase);
const tHole = T.translateZ(LAYER_HEIGHT, hole);
return B.subtract(B.union([...iter(layer0, recurs, NB)]), tHole);
}