88 lines
3.3 KiB
TypeScript
88 lines
3.3 KiB
TypeScript
|
|
"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;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export default function Page() {
|
|||
|
|
const [speed, setSpeed] = useState("800"); // mm/s
|
|||
|
|
const [freq, setFreq] = useState("60"); // kHz
|
|||
|
|
const [spotUm, setSpotUm] = useState("50");// µm
|
|||
|
|
|
|||
|
|
const result = useMemo(() => {
|
|||
|
|
const v = num(speed); // mm/s
|
|||
|
|
const f = num(freq); // kHz
|
|||
|
|
const dUm = num(spotUm); // µm
|
|||
|
|
|
|||
|
|
if (v <= 0 || f <= 0 || dUm <= 0) {
|
|||
|
|
return { spacingUm: 0, spacingMm: 0, overlapPct: 0, pulsesPerMm: 0 };
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// distance per pulse
|
|||
|
|
const spacingUm = v / f; // µm (derives from v(mm/s) / (f(kHz)*1000) * 1000)
|
|||
|
|
const spacingMm = spacingUm / 1000;
|
|||
|
|
const overlapPct = Math.max(0, Math.min(100, 100 * (1 - spacingUm / dUm)));
|
|||
|
|
const pulsesPerMm = (f * 1000) / v;
|
|||
|
|
|
|||
|
|
return { spacingUm, spacingMm, overlapPct, pulsesPerMm };
|
|||
|
|
}, [speed, freq, spotUm]);
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<ToolShell title="Pulse 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">Speed (mm/s)</div>
|
|||
|
|
<Input inputMode="decimal" value={speed} onChange={(e) => setSpeed(e.target.value)} />
|
|||
|
|
</label>
|
|||
|
|
<label className="text-[11px] sm:text-xs">
|
|||
|
|
<div className="mb-1 text-muted-foreground">Frequency (kHz)</div>
|
|||
|
|
<Input inputMode="decimal" value={freq} onChange={(e) => setFreq(e.target.value)} />
|
|||
|
|
</label>
|
|||
|
|
<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>
|
|||
|
|
</CardContent>
|
|||
|
|
</Card>
|
|||
|
|
|
|||
|
|
<Card className="mt-4">
|
|||
|
|
<CardHeader>
|
|||
|
|
<CardTitle className="text-base">Results</CardTitle>
|
|||
|
|
</CardHeader>
|
|||
|
|
<CardContent className="grid gap-3 sm:grid-cols-4">
|
|||
|
|
<div>
|
|||
|
|
<div className="text-sm text-muted-foreground">Pulse spacing</div>
|
|||
|
|
<div className="text-lg">{result.spacingMm.toFixed(4)} mm</div>
|
|||
|
|
<div className="text-xs text-muted-foreground">{result.spacingUm.toFixed(1)} µm</div>
|
|||
|
|
</div>
|
|||
|
|
<div>
|
|||
|
|
<div className="text-sm text-muted-foreground">Overlap</div>
|
|||
|
|
<div className="text-lg">{result.overlapPct.toFixed(1)}%</div>
|
|||
|
|
</div>
|
|||
|
|
<div>
|
|||
|
|
<div className="text-sm text-muted-foreground">Pulses per mm</div>
|
|||
|
|
<div className="text-lg">{result.pulsesPerMm.toFixed(1)}</div>
|
|||
|
|
</div>
|
|||
|
|
<div>
|
|||
|
|
<div className="text-sm text-muted-foreground">Rule of thumb</div>
|
|||
|
|
<div className="text-xs">
|
|||
|
|
60–80% overlap is common for marking; deeper engraving often higher.
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</CardContent>
|
|||
|
|
</Card>
|
|||
|
|
</ToolShell>
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|