Compare commits

...

4 commits

Author SHA1 Message Date
Jan-Henrik Bruhn
3e6a6688e3
Merge pull request #92 from jhbruhn/fix/colormatchtolerance
Some checks failed
Build, Test, and Lint / Build, Test, and Lint (push) Has been cancelled
Draft Release / Draft Release (push) Has been cancelled
Draft Release / Build Web App (push) Has been cancelled
Draft Release / Build Release - macos-latest (push) Has been cancelled
Draft Release / Build Release - ubuntu-latest (push) Has been cancelled
Draft Release / Build Release - windows-latest (push) Has been cancelled
Draft Release / Upload to GitHub Release (push) Has been cancelled
fix: implement validation of color palette number matches using color…
2026-03-29 22:27:38 +02:00
0a80d77455 fix: implement validation of color palette number matches using colordistance 2026-03-29 22:25:32 +02:00
Jan-Henrik Bruhn
dc4fb0221c
Merge pull request #91 from jhbruhn/fix/totalstitches
fix: total stitches from the machine are wrong, we need to use our own
2026-03-29 22:16:09 +02:00
7431327c1c fix: total stitches from the machine are wrong, we need to use our own 2026-03-29 22:14:28 +02:00
3 changed files with 40 additions and 25 deletions

View file

@ -71,12 +71,12 @@ export function ProgressMonitor() {
const isMaskTraceComplete =
machineStatus === MachineStatus.MASK_TRACE_COMPLETE;
// Use PEN stitch count as fallback when machine reports 0 total stitches
const totalStitches = patternInfo
? patternInfo.totalStitches === 0 && displayPattern?.penStitches
? displayPattern.penStitches.stitches.length
: patternInfo.totalStitches
: 0;
// Use our own PEN stitch count as the source of truth for total stitches.
// The machine's patternInfo.totalStitches uses a different counting method than
// currentStitch (e.g. excludes lock stitches), so it can't be used as the max.
const totalStitches = displayPattern?.penStitches
? displayPattern.penStitches.stitches.length
: (patternInfo?.totalStitches ?? 0);
// Use adjustedStitchIndex (from step control) when available, otherwise machine-reported
const currentStitch =
@ -156,8 +156,10 @@ export function ProgressMonitor() {
totalStitches={totalStitches}
lastRolledBackError={lastRolledBackError}
colorBlocks={colorBlocks}
onAdjustPosition={adjustStitchPosition}
onSetPosition={setStitchPosition}
onAdjustPosition={(offset) =>
adjustStitchPosition(offset, totalStitches)
}
onSetPosition={(index) => setStitchPosition(index, totalStitches)}
/>
)}

View file

@ -65,8 +65,8 @@ interface MachineState {
startSewing: () => Promise<void>;
resumeSewing: () => Promise<void>;
deletePattern: () => Promise<void>;
setStitchPosition: (index: number) => Promise<void>;
adjustStitchPosition: (offset: number) => Promise<void>;
setStitchPosition: (index: number, maxStitches?: number) => Promise<void>;
adjustStitchPosition: (offset: number, maxStitches?: number) => Promise<void>;
// Initialization
initialize: () => void;
@ -338,11 +338,11 @@ export const useMachineStore = create<MachineState>((set, get) => ({
},
// Set stitch position to an absolute index
setStitchPosition: async (index: number) => {
setStitchPosition: async (index: number, maxStitches?: number) => {
const { isConnected, service, patternInfo } = get();
if (!isConnected) return;
const totalStitches = patternInfo?.totalStitches || 0;
const totalStitches = maxStitches ?? patternInfo?.totalStitches ?? 0;
const clamped = Math.max(0, Math.min(index, totalStitches));
try {
@ -359,11 +359,11 @@ export const useMachineStore = create<MachineState>((set, get) => ({
},
// Adjust stitch position by a relative offset
adjustStitchPosition: async (offset: number) => {
adjustStitchPosition: async (offset: number, maxStitches?: number) => {
const { sewingProgress, adjustedStitchIndex } = get();
const currentIndex =
adjustedStitchIndex ?? sewingProgress?.currentStitch ?? 0;
await get().setStitchPosition(currentIndex + offset);
await get().setStitchPosition(currentIndex + offset, maxStitches);
},
// Handle automatic stitch rollback for thread errors

View file

@ -57,6 +57,12 @@ export interface ThreadColorInfo {
// Type-safe Brother color data
const brotherColors = brotherColorData as BrotherColor[];
// Maximum RGB Euclidean distance to accept a catalog number match.
// PES catalog numbers from pystitch use a different numbering scheme than our
// Brother color database, so a catalog hit can resolve to the wrong color.
// A match is only trusted if the database entry's RGB is within this distance.
const CATALOG_COLOR_MATCH_THRESHOLD = 50;
/**
* Convert RGB values to hex color string
*/
@ -266,25 +272,32 @@ export function enhanceThreadWithBrotherColor(
): ThreadColorInfo {
const { matchByRGB = true } = options;
// First, try to match by catalog number
if (thread.catalogNumber) {
const brotherInfo = mapThreadCode(thread.catalogNumber);
if (brotherInfo) {
// Found a Brother color match by catalog number - use Brother data
return brotherInfo;
}
}
// Second, try exact RGB matching if enabled (replicates BrotherColor.FromColor logic)
const cleanHex = thread.hex.replace("#", "");
const r = parseInt(cleanHex.slice(0, 2), 16);
const g = parseInt(cleanHex.slice(2, 4), 16);
const b = parseInt(cleanHex.slice(4, 6), 16);
// First, try to match by catalog number — but only accept the match if the
// catalog entry's RGB is close to the thread's actual color. PES catalog
// numbers from pystitch use a different numbering scheme than our Brother
// color database, so a catalog hit can be the wrong color entirely.
if (thread.catalogNumber) {
const brotherInfo = mapThreadCode(thread.catalogNumber);
if (brotherInfo?.rgb) {
const dr = brotherInfo.rgb.r - r;
const dg = brotherInfo.rgb.g - g;
const db = brotherInfo.rgb.b - b;
const distance = Math.sqrt(dr * dr + dg * dg + db * db);
if (distance <= CATALOG_COLOR_MATCH_THRESHOLD) {
return brotherInfo;
}
}
}
// Try exact RGB matching (replicates BrotherColor.FromColor logic)
if (matchByRGB) {
const brotherColor = findBrotherColorByRGB(r, g, b);
if (brotherColor) {
// Found exact RGB match - use Brother data
return brotherColorToThreadInfo(brotherColor);
}
}