AnasSarkiz/magnetic-shutter-remote--01a0f81f
A compact USB‑C rechargeable battery device with BQ25185 charging, 3.3‑V regulation and protection, E73 Bluetooth control, temperature monitoring, status/charge LEDs, shutter/pair/power switches, and a mechanically enclosed Li‑Po battery with docking/antenna provisions.
- Version
- 0.1.9
- License
- unset
- Stars
- 0
enclosure-design/geometry.ts
/** Public jscad-planner operation format consumed by tscircuit CAD renderers.
* Geometry here is mechanical only; no electronic models or footprints change.
* https://github.com/tscircuit/jscad-planner
*/
export type Point3 = [number, number, number];
export type Point2 = [number, number];
export type Rgb = [number, number, number];
export type MechanicalPlan =
| { type: "cuboid"; size: Point3 }
| { type: "cylinder"; radius: number; height: number; center: Point3 }
| { type: "sphere"; radius: number }
| { type: "polygon"; points: Point2[] }
| {
type: "extrudeLinear";
options: { height: number };
shape: MechanicalPlan;
}
| { type: "translate"; vector: Point3; shape: MechanicalPlan }
| { type: "rotate"; angles: Point3; shape: MechanicalPlan }
| { type: "colorize"; color: Rgb; shape: MechanicalPlan }
| {
type: "union" | "subtract" | "intersect" | "hull";
shapes: MechanicalPlan[];
};
export function move(vector: Point3, shape: MechanicalPlan): MechanicalPlan {
return { type: "translate", vector, shape };
}
export function box(size: Point3, center: Point3): MechanicalPlan {
return move(center, { type: "cuboid", size });
}
export function cylinder(options: {
x: number;
y: number;
z: number;
radius: number;
height: number;
}): MechanicalPlan {
return {
type: "cylinder",
radius: options.radius,
height: options.height,
center: [options.x, options.y, options.z + options.height / 2],
};
}
export function union(...shapes: MechanicalPlan[]): MechanicalPlan {
return { type: "union", shapes };
}
export function subtract(...shapes: MechanicalPlan[]): MechanicalPlan {
return { type: "subtract", shapes };
}
export function hull(...shapes: MechanicalPlan[]): MechanicalPlan {
return { type: "hull", shapes };
}
export function colored(color: Rgb, shape: MechanicalPlan): MechanicalPlan {
return { type: "colorize", color, shape };
}
export function roundedBox(options: {
width: number;
length: number;
radius: number;
z: number;
height: number;
x?: number;
y?: number;
}): MechanicalPlan {
const { width, length, radius, z, height, x = 0, y = 0 } = options;
if (height <= 0 || radius <= 0 || radius * 2 >= Math.min(width, length)) {
throw new Error("Invalid rounded enclosure dimensions");
}
const points: Point2[] = [];
for (let corner = 0; corner < 4; corner++) {
const cx =
corner === 0 || corner === 3 ? width / 2 - radius : -width / 2 + radius;
const cy = corner < 2 ? length / 2 - radius : -length / 2 + radius;
for (let segment = 0; segment <= 12; segment++) {
const angle = (corner * Math.PI) / 2 + (segment * Math.PI) / 24;
points.push([
cx + radius * Math.cos(angle),
cy + radius * Math.sin(angle),
]);
}
}
return move([x, y, z], {
type: "extrudeLinear",
options: { height },
shape: { type: "polygon", points },
});
}
export function ring(options: {
x: number;
y: number;
z: number;
outerRadius: number;
innerRadius: number;
height: number;
}): MechanicalPlan {
return subtract(
cylinder({ ...options, radius: options.outerRadius }),
cylinder({
...options,
radius: options.innerRadius,
z: options.z - 0.01,
height: options.height + 0.02,
}),
);
}
export function bar(options: {
start: Point3;
end: Point3;
radius: number;
height: number;
}): MechanicalPlan {
return hull(
cylinder({
x: options.start[0],
y: options.start[1],
z: options.start[2],
radius: options.radius,
height: options.height,
}),
cylinder({
x: options.end[0],
y: options.end[1],
z: options.end[2],
radius: options.radius,
height: options.height,
}),
);
}