function ShapePackingCalculator() { const [mode, setMode] = useState('2d'); // 2d or 3d const [containerType, setContainerType] = useState('rectangle'); const [itemType, setItemType] = useState('rectangle'); const [cWidth, setCWidth] = useState('100'); const [cHeight, setCHeight] = useState('100'); const [cDepth, setCDepth] = useState('100'); const [iWidth, setIWidth] = useState('10'); const [iHeight, setIHeight] = useState('10'); const [iDepth, setIDepth] = useState('10'); const [allowRotation, setAllowRotation] = useState(true); const [result, setResult] = useState(null); const calculate = () => { const cw = parseFloat(cWidth); const ch = parseFloat(cHeight); const cd = parseFloat(cDepth); const iw = parseFloat(iWidth); const ih = parseFloat(iHeight); const id = parseFloat(iDepth); let count = 0; let efficiency = 0; if (mode === '2d') { if (containerType === 'rectangle') { if (itemType === 'rectangle') { // Try both orientations to maximize const count1 = Math.floor(cw / iw) * Math.floor(ch / ih); const count2 = allowRotation ? Math.floor(cw / ih) * Math.floor(ch / iw) : 0; let bestCount = Math.max(count1, count2); if (allowRotation) { // Try 2-block split packing (Vertical split) for (let splitW = 0; splitW <= cw; splitW += Math.min(iw, ih)) { const part1 = Math.floor(splitW / iw) * Math.floor(ch / ih) + Math.floor((cw - splitW) / ih) * Math.floor(ch / iw); const part2 = Math.floor(splitW / ih) * Math.floor(ch / iw) + Math.floor((cw - splitW) / iw) * Math.floor(ch / ih); bestCount = Math.max(bestCount, part1, part2); } // Try 2-block split packing (Horizontal split) for (let splitH = 0; splitH <= ch; splitH += Math.min(iw, ih)) { const part1 = Math.floor(cw / iw) * Math.floor(splitH / ih) + Math.floor(cw / ih) * Math.floor((ch - splitH) / iw); const part2 = Math.floor(cw / ih) * Math.floor(splitH / iw) + Math.floor(cw / iw) * Math.floor((ch - splitH) / ih); bestCount = Math.max(bestCount, part1, part2); } } count = bestCount; efficiency = ((count * iw * ih) / (cw * ch) * 100).toFixed(2); } else if (itemType === 'circle') { const r = iw / 2; const d = iw; const sqCount = Math.floor(cw / d) * Math.floor(ch / d); const rowDist = d * Math.sqrt(3) / 2; const rows = Math.floor((ch - d) / rowDist) + 1; const colsEven = Math.floor(cw / d); const colsOdd = Math.floor((cw - r) / d); const hexCount = Math.floor(rows / 2) * colsEven + Math.ceil(rows / 2) * colsOdd; count = Math.max(sqCount, hexCount); efficiency = ((count * Math.PI * r * r) / (cw * ch) * 100).toFixed(2); } } } else { const containerVol = cw * ch * cd; if (itemType === 'rectangle') { const orientations = [ [iw, ih, id], [iw, id, ih], [ih, iw, id], [ih, id, iw], [id, iw, ih], [id, ih, iw] ]; let bestCount = 0; const activeOrientations = allowRotation ? orientations : [orientations[0]]; activeOrientations.forEach(([w, h, d]) => { const c = Math.floor(cw / w) * Math.floor(ch / h) * Math.floor(cd / d); if (c > bestCount) bestCount = c; }); count = bestCount; efficiency = ((count * iw * ih * id) / containerVol * 100).toFixed(2); } else if (itemType === 'circle') { const r = iw / 2; const d = iw; const scCount = Math.floor(cw / d) * Math.floor(ch / d) * Math.floor(cd / d); const fccCount = Math.floor(Math.PI / (3 * Math.sqrt(2)) * (containerVol / (4 / 3 * Math.PI * r ** 3))); count = Math.max(scCount, Math.floor(fccCount * 0.95)); efficiency = ((count * (4 / 3) * Math.PI * r ** 3) / containerVol * 100).toFixed(2); } } setResult({ count, efficiency }); }; return (

📦 Advanced Shape Packing ({mode.toUpperCase()})

setCWidth(e.target.value)} />
setCHeight(e.target.value)} />
{mode === '3d' && (
setCDepth(e.target.value)} />
)}
setIWidth(e.target.value)} />
{itemType === 'rectangle' && (
setIHeight(e.target.value)} />
)} {itemType === 'rectangle' && mode === '3d' && (
setIDepth(e.target.value)} />
)}
{itemType === 'rectangle' && (
setAllowRotation(e.target.checked)} id="rot" />
)} {result && (
ESTIMATED COUNT
{result.count}
items fit in container
Efficiency: 80 ? 'var(--success)' : 'var(--text-primary)' }}>{result.efficiency}%
)}
); } // Export to global registry window.ShapePackingCalculator = ShapePackingCalculator;