Files
cadSet/text-to-cad/models/implicits/hilbert-curve-block.implicit.js
T
2026-07-22 19:38:36 +08:00

151 lines
6.0 KiB
JavaScript

const GLSL = `
float sdBox(vec3 p, vec3 b) {
vec3 q = abs(p) - b;
return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0);
}
float sdSegment2(vec2 p, vec2 a, vec2 b) {
vec2 pa = p - a;
vec2 ba = b - a;
float h = clamp(dot(pa, ba) / max(dot(ba, ba), 0.0001), 0.0, 1.0);
return length(pa - ba * h);
}
vec2 hilbertGridPoint2(float i) {
float index = clamp(floor(i + 0.5), 0.0, 63.0);
if (index < 0.5) { return vec2(0.0, 0.0); }
if (index < 1.5) { return vec2(0.0, 1.0); }
if (index < 2.5) { return vec2(1.0, 1.0); }
if (index < 3.5) { return vec2(1.0, 0.0); }
if (index < 4.5) { return vec2(2.0, 0.0); }
if (index < 5.5) { return vec2(3.0, 0.0); }
if (index < 6.5) { return vec2(3.0, 1.0); }
if (index < 7.5) { return vec2(2.0, 1.0); }
if (index < 8.5) { return vec2(2.0, 2.0); }
if (index < 9.5) { return vec2(3.0, 2.0); }
if (index < 10.5) { return vec2(3.0, 3.0); }
if (index < 11.5) { return vec2(2.0, 3.0); }
if (index < 12.5) { return vec2(1.0, 3.0); }
if (index < 13.5) { return vec2(1.0, 2.0); }
if (index < 14.5) { return vec2(0.0, 2.0); }
if (index < 15.5) { return vec2(0.0, 3.0); }
if (index < 16.5) { return vec2(0.0, 4.0); }
if (index < 17.5) { return vec2(1.0, 4.0); }
if (index < 18.5) { return vec2(1.0, 5.0); }
if (index < 19.5) { return vec2(0.0, 5.0); }
if (index < 20.5) { return vec2(0.0, 6.0); }
if (index < 21.5) { return vec2(0.0, 7.0); }
if (index < 22.5) { return vec2(1.0, 7.0); }
if (index < 23.5) { return vec2(1.0, 6.0); }
if (index < 24.5) { return vec2(2.0, 6.0); }
if (index < 25.5) { return vec2(2.0, 7.0); }
if (index < 26.5) { return vec2(3.0, 7.0); }
if (index < 27.5) { return vec2(3.0, 6.0); }
if (index < 28.5) { return vec2(3.0, 5.0); }
if (index < 29.5) { return vec2(2.0, 5.0); }
if (index < 30.5) { return vec2(2.0, 4.0); }
if (index < 31.5) { return vec2(3.0, 4.0); }
if (index < 32.5) { return vec2(4.0, 4.0); }
if (index < 33.5) { return vec2(5.0, 4.0); }
if (index < 34.5) { return vec2(5.0, 5.0); }
if (index < 35.5) { return vec2(4.0, 5.0); }
if (index < 36.5) { return vec2(4.0, 6.0); }
if (index < 37.5) { return vec2(4.0, 7.0); }
if (index < 38.5) { return vec2(5.0, 7.0); }
if (index < 39.5) { return vec2(5.0, 6.0); }
if (index < 40.5) { return vec2(6.0, 6.0); }
if (index < 41.5) { return vec2(6.0, 7.0); }
if (index < 42.5) { return vec2(7.0, 7.0); }
if (index < 43.5) { return vec2(7.0, 6.0); }
if (index < 44.5) { return vec2(7.0, 5.0); }
if (index < 45.5) { return vec2(6.0, 5.0); }
if (index < 46.5) { return vec2(6.0, 4.0); }
if (index < 47.5) { return vec2(7.0, 4.0); }
if (index < 48.5) { return vec2(7.0, 3.0); }
if (index < 49.5) { return vec2(7.0, 2.0); }
if (index < 50.5) { return vec2(6.0, 2.0); }
if (index < 51.5) { return vec2(6.0, 3.0); }
if (index < 52.5) { return vec2(5.0, 3.0); }
if (index < 53.5) { return vec2(4.0, 3.0); }
if (index < 54.5) { return vec2(4.0, 2.0); }
if (index < 55.5) { return vec2(5.0, 2.0); }
if (index < 56.5) { return vec2(5.0, 1.0); }
if (index < 57.5) { return vec2(4.0, 1.0); }
if (index < 58.5) { return vec2(4.0, 0.0); }
if (index < 59.5) { return vec2(5.0, 0.0); }
if (index < 60.5) { return vec2(6.0, 0.0); }
if (index < 61.5) { return vec2(6.0, 1.0); }
if (index < 62.5) { return vec2(7.0, 1.0); }
return vec2(7.0, 0.0);
}
vec2 hilbertBlockPoint(float i) {
return (hilbertGridPoint2(i) - vec2(3.5)) * cellSize;
}
float channelField(vec2 p) {
float d = 100000.0;
for (int i = 0; i < 63; i += 1) {
float fi = float(i);
d = min(d, sdSegment2(p, hilbertBlockPoint(fi), hilbertBlockPoint(fi + 1.0)));
}
return d;
}
float sdf(vec3 p) {
float extent = cellSize * 4.1;
float plate = sdBox(p + vec3(0.0, 0.0, plateThickness * 0.18), vec3(extent, extent, plateThickness * 0.42));
float channel = max(channelField(p.xy) - channelWidth, abs(p.z - plateThickness * 0.18) - plateThickness * 0.34);
float raisedRim = max(channelField(p.xy) - channelWidth * 1.35, abs(p.z - plateThickness * 0.42) - liftHeight * 0.36);
return min(max(plate, -channel), raisedRim);
}
vec3 color(vec3 p, vec3 normal) {
float path = smoothstep(channelWidth * 1.8, channelWidth * 0.35, channelField(p.xy));
float grid = 0.5 + 0.5 * sin((p.x + p.y) * 0.22);
vec3 plateColor = mix(baseColor * 0.52, baseColor, 0.45 + 0.55 * normal.z);
vec3 pathColor = mix(accentColor * 0.72, accentColor, grid);
return mix(plateColor, pathColor, path);
}
`;
export default {
schema: "implicit.js/0.1.0",
name: "2D Hilbert curve block",
description: "A true order-3 planar Hilbert curve cut into a solid plate with a raised colored trace.",
units: "mm",
params: {
cellSize: { type: "number", label: "Cell size", min: 3.5, max: 8, step: 0.1, default: 5.3, unit: "mm" },
channelWidth: { type: "number", label: "Channel width", min: 0.45, max: 2.4, step: 0.05, default: 1.15, unit: "mm" },
plateThickness: { type: "number", label: "Plate thickness", min: 1.6, max: 6, step: 0.1, default: 3.2, unit: "mm" },
liftHeight: { type: "number", label: "Trace lift", min: 0.3, max: 2.4, step: 0.05, default: 1.0, unit: "mm" },
baseColor: { type: "color", label: "Plate color", default: "#a5b4fc" },
accentColor: { type: "color", label: "Trace color", default: "#ccff33" }
},
animations: {
channelBreath: {
label: "Channel breath",
duration: 4.2,
loop: true,
update({ progress, set }) {
const wave = Math.sin(progress * Math.PI * 2);
set("channelWidth", 1.15 + wave * 0.42);
set("liftHeight", 1.0 + (wave * 0.5 + 0.5) * 0.75);
}
}
},
bounds: ({ params }) => {
const extent = params.cellSize * 4.45 + params.channelWidth + 4;
const z = params.plateThickness + params.liftHeight + 3;
return [[-extent, -extent, -z], [extent, extent, z]];
},
render: ({ params }) => ({
steps: 190,
stepScale: 0.7,
maxStep: Math.max(params.channelWidth * 3.5, 1.1),
epsilon: Math.max(params.channelWidth * 0.012, 0.004),
normalEpsilon: Math.max(params.channelWidth * 0.08, 0.035)
}),
glsl: GLSL
};