File size: 2,986 Bytes
336fa2c
469b970
6a25ae8
469b970
 
6a25ae8
336fa2c
 
469b970
 
 
 
 
 
336fa2c
 
6a25ae8
 
 
 
 
 
 
 
 
336fa2c
469b970
 
 
6a25ae8
336fa2c
469b970
 
 
 
336fa2c
469b970
 
 
336fa2c
 
469b970
6a25ae8
 
469b970
336fa2c
469b970
6a25ae8
 
469b970
336fa2c
469b970
 
 
 
6a25ae8
 
 
 
 
 
469b970
 
6a25ae8
336fa2c
 
6a25ae8
469b970
6a25ae8
336fa2c
 
 
469b970
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/**
 * engine/optimizer.js
 * ืžื ื•ืข ืื™ืžืคื•ื–ื™ืฆื™ื” (Imposition Engine) - V2 (Hardened)
 * ====================================
 * ืชืคืงื™ื“: ืœื—ืฉื‘ ืžืชืžื˜ื™ืช ื›ืžื” ื™ื—ื™ื“ื•ืช ื ื›ื ืกื•ืช ื‘ื’ื™ืœื™ื•ืŸ SRA3.
 * ืชื•ืงืŸ: ื”ื•ืกืคืช Epsilon Guard ืœืžื ื™ืขืช ื—ื™ืชื•ืš ืฉื’ื•ื™ ื‘ื’ืœืœ Floating Point (ืœืžืฉืœ ืžื•ื ืข ืž-2.99999998 ืœื”ืคื•ืš ืœ-2).
 */

const MACHINE_SPECS = {
    // HP Indigo 7K specs (SRA3)
    sheetWidth: 320,  // mm
    sheetHeight: 450, // mm
    margins: 5,       // mm (safety margin for gripper/bleed)
    gutter: 2         // mm (space between cuts)
};

/**
 * ืคื•ื ืงืฆื™ื™ืช ืขื–ืจ ืœื—ืœื•ืงื” ืžื•ื’ื ืช ืžืคื ื™ ืฉื’ื™ืื•ืช Floating Point
 */
function safeFloorDivision(total, part) {
    if (part <= 0) return 0;
    // Number.EPSILON ืžื—ืคื” ื‘ื“ื™ื•ืง ืขืœ ื”ืžืกืคืจื™ื ืฉื™ื•ืจื“ื™ื ื‘-0.000000001
    return Math.floor((total / part) + Number.EPSILON);
}

/**
 * ื—ื™ืฉื•ื‘ ืคืจื™ืกื” ืื•ืคื˜ื™ืžืœื™ืช (Best Fit)
 * @param {number} prodWidth - ืจื•ื—ื‘ ืžื•ืฆืจ ื‘ืž"ืž
 * @param {number} prodHeight - ื’ื•ื‘ื” ืžื•ืฆืจ ื‘ืž"ืž
 * @returns {object} { ups, layout, efficiency }
 */
function calculateImposition(prodWidth, prodHeight) {
    // ืฉื˜ื— ื ื˜ื• ืœื”ื“ืคืกื” (ืœืื—ืจ ื”ืคื—ืชืช ืฉื•ืœื™ ืžื›ื•ื ื”)
    const safeW = MACHINE_SPECS.sheetWidth - (MACHINE_SPECS.margins * 2);
    const safeH = MACHINE_SPECS.sheetHeight - (MACHINE_SPECS.margins * 2);

    // ื”ื’ื ื” ืžืคื ื™ ืงืœื˜ ืœื ืชืงื™ืŸ
    if (!prodWidth || !prodHeight || prodWidth <= 0 || prodHeight <= 0) {
        return { ups: 0, layout: 'error', efficiency: 0 };
    }

    // ืื•ืคืฆื™ื” ื': ื™ืฉืจ (Portrait)
    const fitW_A = safeFloorDivision(safeW, prodWidth + MACHINE_SPECS.gutter);
    const fitH_A = safeFloorDivision(safeH, prodHeight + MACHINE_SPECS.gutter);
    const total_A = fitW_A * fitH_A;

    // ืื•ืคืฆื™ื” ื‘': ืžืกื•ื‘ื‘ (Landscape)
    const fitW_B = safeFloorDivision(safeW, prodHeight + MACHINE_SPECS.gutter);
    const fitH_B = safeFloorDivision(safeH, prodWidth + MACHINE_SPECS.gutter);
    const total_B = fitW_B * fitH_B;

    // ื‘ื—ื™ืจืช ื”ืžื ืฆื— (ืื™ืคื” ื ื›ื ืกื™ื ื™ื•ืชืจ?)
    const maxUps = Math.max(total_A, total_B);
    const bestLayout = total_A >= total_B ? 'portrait' : 'landscape';

    // ื˜ื™ืคื•ืœ ืืœื’ื ื˜ื™ ื‘ืžื•ืฆืจ ื’ื“ื•ืœ ืžื“ื™ (ื”ื’ื ื” ืขืœ ื”ืžืขืจื›ืช ืžืงืจืฉ ืขืœ ื—ืœื•ืงื” ื‘ืืคืก)
    if (maxUps === 0) {
        return { ups: 0, layout: 'error', efficiency: "0.0%" };
    }

    // ื—ื™ืฉื•ื‘ ืื—ื•ื– ื ื™ืฆื•ืœ ื”ื ื™ื™ืจ (Efficiency) - ื”ืขืจื”: ืžื—ื•ืฉื‘ ืžื•ืœ ืฉื˜ื— ื‘ืจื•ื˜ื• ื‘ื›ื•ื•ื ื” ืชื—ื™ืœื”
    const usedArea = maxUps * prodWidth * prodHeight;
    const totalArea = MACHINE_SPECS.sheetWidth * MACHINE_SPECS.sheetHeight;
    const efficiencyNum = ((usedArea / totalArea) * 100).toFixed(1);

    return {
        ups: maxUps,
        layout: bestLayout,
        efficiency: efficiencyNum + "%"
    };
}

module.exports = { calculateImposition };