Initial commit
This commit is contained in:
commit
78f8d225ee
21173 changed files with 2907774 additions and 0 deletions
97
app/laser-toolkit/hatch-overlap/page.tsx
Normal file
97
app/laser-toolkit/hatch-overlap/page.tsx
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
"use client";
|
||||
|
||||
import { useMemo, useState } from "react";
|
||||
import ToolShell from "@/components/toolkit/ToolShell";
|
||||
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
||||
import { Input } from "@/components/ui/input";
|
||||
|
||||
function num(v: string) {
|
||||
const n = parseFloat(v);
|
||||
return Number.isFinite(n) ? n : 0;
|
||||
}
|
||||
|
||||
const UM_PER_INCH = 25400;
|
||||
|
||||
export default function Page() {
|
||||
const [spotUm, setSpotUm] = useState("60");
|
||||
const [gapUm, setGapUm] = useState("40");
|
||||
const [lpi, setLpi] = useState("635"); // 635 LPI ≈ 40 µm gap
|
||||
|
||||
// Keep gap and LPI linked both ways
|
||||
function onGapChange(v: string) {
|
||||
setGapUm(v);
|
||||
const g = num(v);
|
||||
setLpi(g > 0 ? (UM_PER_INCH / g).toFixed(2) : "");
|
||||
}
|
||||
function onLpiChange(v: string) {
|
||||
setLpi(v);
|
||||
const L = num(v);
|
||||
setGapUm(L > 0 ? (UM_PER_INCH / L).toFixed(2) : "");
|
||||
}
|
||||
|
||||
const overlap = useMemo(() => {
|
||||
const d = num(spotUm);
|
||||
const g = num(gapUm);
|
||||
if (d <= 0 || g <= 0) return 0;
|
||||
return Math.max(0, Math.min(100, 100 * (1 - g / d)));
|
||||
}, [spotUm, gapUm]);
|
||||
|
||||
const gapMm = (num(gapUm) / 1000) || 0;
|
||||
const spotMm = (num(spotUm) / 1000) || 0;
|
||||
|
||||
return (
|
||||
<ToolShell title="Hatch Overlap">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-base">Inputs</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="grid gap-3 sm:grid-cols-3">
|
||||
<label className="text-[11px] sm:text-xs">
|
||||
<div className="mb-1 text-muted-foreground">Spot size (µm)</div>
|
||||
<Input inputMode="decimal" value={spotUm} onChange={(e) => setSpotUm(e.target.value)} />
|
||||
</label>
|
||||
<label className="text-[11px] sm:text-xs">
|
||||
<div className="mb-1 text-muted-foreground">Hatch gap (µm)</div>
|
||||
<Input inputMode="decimal" value={gapUm} onChange={(e) => onGapChange(e.target.value)} />
|
||||
</label>
|
||||
<label className="text-[11px] sm:text-xs">
|
||||
<div className="mb-1 text-muted-foreground">Hatch LPI</div>
|
||||
<Input inputMode="decimal" value={lpi} onChange={(e) => onLpiChange(e.target.value)} />
|
||||
</label>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="mt-4">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-base">Result</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="grid gap-3 sm:grid-cols-4">
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground">Overlap</div>
|
||||
<div className="text-lg">{overlap.toFixed(1)}%</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground">Gap</div>
|
||||
<div className="text-lg">{gapMm.toFixed(4)} mm</div>
|
||||
<div className="text-xs text-muted-foreground">{num(gapUm).toFixed(1)} µm</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground">Spot Ø</div>
|
||||
<div className="text-lg">{spotMm.toFixed(4)} mm</div>
|
||||
<div className="text-xs text-muted-foreground">{num(spotUm).toFixed(1)} µm</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground">From LPI</div>
|
||||
<div className="text-lg">
|
||||
{(UM_PER_INCH / Math.max(1, num(lpi)) / 1000).toFixed(4)} mm
|
||||
</div>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
{(UM_PER_INCH / Math.max(1, num(lpi))).toFixed(1)} µm
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</ToolShell>
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue