initial
This commit is contained in:
commit
4cda1ca41b
72 files changed
+8169
No files matched your search
@@ -0,0 +1,107 @@
|
||||
---
|
||||
/**
|
||||
* Grid objects: wireframe solids drawn as technical line drawings.
|
||||
* Single stroke in currentColor, even width, no fills. The geometry is computed
|
||||
* at build time so the markup stays small and the stroke stays exact.
|
||||
* Kinds: sphere (a model seen from every side), cube (a built structure),
|
||||
* plane (one element lifted out for inspection), wave (a signal over time).
|
||||
*/
|
||||
interface Props { kind: 'sphere' | 'cube' | 'plane' | 'wave'; class?: string }
|
||||
const { kind, class: className } = Astro.props;
|
||||
|
||||
const S = 400;
|
||||
const f = (n: number) => Math.round(n * 10) / 10;
|
||||
const poly = (pts: [number, number][]) => pts.map(([x, y]) => `${f(x)},${f(y)}`).join(' ');
|
||||
|
||||
/* Isometric projection of a 3D point (x right, y up, z towards the viewer's left). */
|
||||
const ISO = { cx: S / 2, cy: S / 2, c30: Math.cos(Math.PI / 6), s30: Math.sin(Math.PI / 6) };
|
||||
const iso = (x: number, y: number, z: number, cy = ISO.cy): [number, number] =>
|
||||
[ISO.cx + (x - z) * ISO.c30, cy + (x + z) * ISO.s30 - y];
|
||||
|
||||
const lines: string[] = [];
|
||||
|
||||
if (kind === 'sphere') {
|
||||
const R = 150, tilt = (22 * Math.PI) / 180, N = 48;
|
||||
const p3 = (lat: number, lon: number): [number, number] => {
|
||||
const x = R * Math.cos(lat) * Math.sin(lon);
|
||||
const y = R * Math.sin(lat);
|
||||
const z = R * Math.cos(lat) * Math.cos(lon);
|
||||
const y2 = y * Math.cos(tilt) - z * Math.sin(tilt);
|
||||
return [ISO.cx + x, ISO.cy - y2];
|
||||
};
|
||||
// Parallels every 20 degrees, meridians every 22.5 degrees (8 great circles).
|
||||
for (let d = -80; d <= 80; d += 20) {
|
||||
const lat = (d * Math.PI) / 180;
|
||||
const pts: [number, number][] = [];
|
||||
for (let i = 0; i <= N; i++) pts.push(p3(lat, (i / N) * 2 * Math.PI));
|
||||
lines.push(poly(pts));
|
||||
}
|
||||
for (let m = 0; m < 8; m++) {
|
||||
const lon = (m * Math.PI) / 8;
|
||||
const pts: [number, number][] = [];
|
||||
for (let i = 0; i <= N; i++) pts.push(p3((i / N) * 2 * Math.PI - Math.PI, lon));
|
||||
lines.push(poly(pts));
|
||||
}
|
||||
lines.push(`circle:${R}`);
|
||||
}
|
||||
|
||||
if (kind === 'cube') {
|
||||
const n = 4, u = 46, L = n * u, cy = ISO.cy + L * 0.5;
|
||||
for (let i = 0; i <= n; i++) {
|
||||
const t = i * u;
|
||||
// top face (y = L)
|
||||
lines.push(poly([iso(t, L, 0, cy), iso(t, L, L, cy)]));
|
||||
lines.push(poly([iso(0, L, t, cy), iso(L, L, t, cy)]));
|
||||
// front-right face (z = 0): x by y
|
||||
lines.push(poly([iso(t, 0, 0, cy), iso(t, L, 0, cy)]));
|
||||
lines.push(poly([iso(0, t, 0, cy), iso(L, t, 0, cy)]));
|
||||
// front-left face (x = 0): z by y
|
||||
lines.push(poly([iso(0, 0, t, cy), iso(0, L, t, cy)]));
|
||||
lines.push(poly([iso(0, t, 0, cy), iso(0, t, L, cy)]));
|
||||
}
|
||||
}
|
||||
|
||||
if (kind === 'plane') {
|
||||
const n = 6, u = 34, L = n * u, cy = ISO.cy + 20, h = 96, tx = 2, tz = 2;
|
||||
for (let i = 0; i <= n; i++) {
|
||||
const t = i * u;
|
||||
lines.push(poly([iso(t, 0, 0, cy), iso(t, 0, L, cy)]));
|
||||
lines.push(poly([iso(0, 0, t, cy), iso(L, 0, t, cy)]));
|
||||
}
|
||||
const c: [number, number][] = [[tx, tz], [tx + 1, tz], [tx + 1, tz + 1], [tx, tz + 1]];
|
||||
const top = c.map(([x, z]) => iso(x * u, h, z * u, cy));
|
||||
lines.push(poly([...top, top[0]]));
|
||||
c.forEach(([x, z], i) => lines.push(poly([iso(x * u, 0, z * u, cy), top[i]])));
|
||||
}
|
||||
|
||||
if (kind === 'wave') {
|
||||
const nx = 12, nz = 8, u = 26, cy = ISO.cy + 10, A = 26;
|
||||
const yAt = (x: number, z: number) => A * Math.sin((x / nx) * Math.PI * 2 - 0.6) * Math.cos((z / nz) * Math.PI * 0.9);
|
||||
const P = (x: number, z: number) => iso((x - nx / 2) * u, yAt(x, z), (z - nz / 2) * u, cy);
|
||||
for (let z = 0; z <= nz; z++) {
|
||||
const pts: [number, number][] = [];
|
||||
for (let x = 0; x <= nx; x++) pts.push(P(x, z));
|
||||
lines.push(poly(pts));
|
||||
}
|
||||
for (let x = 0; x <= nx; x++) {
|
||||
const pts: [number, number][] = [];
|
||||
for (let z = 0; z <= nz; z++) pts.push(P(x, z));
|
||||
lines.push(poly(pts));
|
||||
}
|
||||
}
|
||||
---
|
||||
<svg class:list={['grid-object', className]} viewBox={`0 0 ${S} ${S}`} aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="none" stroke="currentColor" stroke-width="1.25" stroke-linejoin="round" stroke-linecap="round" vector-effect="non-scaling-stroke">
|
||||
{lines.map((l) => l.startsWith('circle:')
|
||||
? <circle cx={S / 2} cy={S / 2} r={Number(l.slice(7))} />
|
||||
: <polyline points={l} />)}
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
<style>
|
||||
.grid-object {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
color: var(--ink);
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user