diff --git a/src/components/DimensionsView.tsx b/src/components/DimensionsView.tsx index 524ca27..1bfa81f 100644 --- a/src/components/DimensionsView.tsx +++ b/src/components/DimensionsView.tsx @@ -110,6 +110,16 @@ export function DimensionsView({ data, headers, onEdit, onSaveRow, onCaptureStat }, [groups, showOnlyInconsistent]); const nearDuplicateClusters = useMemo((): NearDuplicateCluster[] => { + // Two groups are "similar" if every sorted dimension pair differs by ≤15% + // (keys are already sorted ascending, e.g. "15x20x29") + const THRESHOLD = 0.15; + + const maxRelativeDiff = (keyA: string, keyB: string): number => { + const a = keyA.split('x').map(Number); + const b = keyB.split('x').map(Number); + return Math.max(...a.map((v, i) => Math.abs(v - b[i]) / Math.max(v, b[i], 0.001))); + }; + const validGroups = groups.filter(g => g.volume > 0); const assignedKeys = new Set(); const clusters: NearDuplicateCluster[] = []; @@ -125,13 +135,9 @@ export function DimensionsView({ data, headers, onEdit, onSaveRow, onCaptureStat const b = validGroups[j]; if (assignedKeys.has(b.key)) continue; - // Check if b is within 5% volume of every group already in the cluster - const isNear = cluster.every(g => { - const maxVol = Math.max(g.volume, b.volume); - return Math.abs(g.volume - b.volume) / maxVol <= 0.05; - }); - - if (isNear) { + // b must be similar to every group already in the cluster + const isSimilar = cluster.every(g => maxRelativeDiff(g.key, b.key) <= THRESHOLD); + if (isSimilar) { cluster.push(b); assignedKeys.add(b.key); } @@ -139,9 +145,13 @@ export function DimensionsView({ data, headers, onEdit, onSaveRow, onCaptureStat if (cluster.length >= 2) { const volumes = cluster.map(g => g.volume); - const maxVol = Math.max(...volumes); - const minVol = Math.min(...volumes); - const maxDiffPct = ((maxVol - minVol) / maxVol) * 100; + // Max dimension-wise diff across all pairs in the cluster + let maxDiffPct = 0; + for (let x = 0; x < cluster.length; x++) { + for (let y = x + 1; y < cluster.length; y++) { + maxDiffPct = Math.max(maxDiffPct, maxRelativeDiff(cluster[x].key, cluster[y].key) * 100); + } + } clusters.push({ groups: cluster, volumes, maxDiffPct }); } } @@ -244,7 +254,7 @@ export function DimensionsView({ data, headers, onEdit, onSaveRow, onCaptureStat Possible data entry errors - {nearDuplicateClusters.length} cluster{nearDuplicateClusters.length !== 1 ? 's' : ''} within 5% volume + {nearDuplicateClusters.length} cluster{nearDuplicateClusters.length !== 1 ? 's' : ''} with similar dimensions (≤15% per axis) {nearDuplicateClusters.map((cluster, ci) => ( @@ -266,7 +276,7 @@ export function DimensionsView({ data, headers, onEdit, onSaveRow, onCaptureStat ))} - — diff. {cluster.maxDiffPct.toFixed(1)}% + — max axis diff {cluster.maxDiffPct.toFixed(1)}%