76 lines
1.9 KiB
Go

package layout
import (
"printer.backend/internal/model"
)
// Footprint returns the physical width and height one item occupies on the plate (mm).
// Includes bleed on all sides and the item's margin as a safe zone.
func Footprint(spec model.ItemSpec) (width, height float64) {
w := spec.SizeMM + 2*spec.BleedMM + 2*spec.MarginMM
return w, w
}
// CellPitch returns width and height of one grid cell (footprint + spacing between items).
func CellPitch(spec model.ItemSpec, spacingMM float64) (width, height float64) {
fw, fh := Footprint(spec)
return fw + spacingMM, fh + spacingMM
}
// Pack computes the maximum grid of items that fit on the plate.
func Pack(plate model.Plate, spec model.ItemSpec, spacingMM float64) model.LayoutPreview {
pw := plate.PrintableWidth()
ph := plate.PrintableHeight()
fw, fh := Footprint(spec)
cw, ch := CellPitch(spec, spacingMM)
cols, rows := gridCount(pw, ph, cw, ch)
count := cols * rows
ox := plate.MarginLeft
oy := plate.MarginTop
positions := make([]model.LayoutPosition, 0, count)
for row := 0; row < rows; row++ {
for col := 0; col < cols; col++ {
positions = append(positions, model.LayoutPosition{
XMM: ox + float64(col)*cw,
YMM: oy + float64(row)*ch,
})
}
}
return model.LayoutPreview{
PlateWidthMM: plate.WidthMM,
PlateHeightMM: plate.HeightMM,
PrintableXMM: ox,
PrintableYMM: oy,
PrintableWMM: pw,
PrintableHMM: ph,
CellWidthMM: cw,
CellHeightMM: ch,
FootprintWMM: fw,
FootprintHMM: fh,
SpacingMM: spacingMM,
Columns: cols,
Rows: rows,
Count: count,
Positions: positions,
}
}
func gridCount(printableW, printableH, cellW, cellH float64) (cols, rows int) {
if printableW <= 0 || printableH <= 0 || cellW <= 0 || cellH <= 0 {
return 0, 0
}
cols = int(printableW / cellW)
rows = int(printableH / cellH)
if cols < 0 {
cols = 0
}
if rows < 0 {
rows = 0
}
return cols, rows
}