Added PDF Generation

This commit is contained in:
2026-05-26 17:11:09 +02:00
parent c5d2e32355
commit af4c944de7
12 changed files with 525 additions and 34 deletions
+6 -17
View File
@@ -4,25 +4,14 @@ 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.
// Item spacing uses the SVG viewport size (spec.SizeMM); bleed/margin/padding live inside the template.
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)
itemW := spec.SizeMM
cw := itemW + spacingMM
ch := itemW + spacingMM
cols, rows := gridCount(pw, ph, cw, ch)
count := cols * rows
@@ -49,8 +38,8 @@ func Pack(plate model.Plate, spec model.ItemSpec, spacingMM float64) model.Layou
PrintableHMM: ph,
CellWidthMM: cw,
CellHeightMM: ch,
FootprintWMM: fw,
FootprintHMM: fh,
FootprintWMM: itemW,
FootprintHMM: itemW,
SpacingMM: spacingMM,
Columns: cols,
Rows: rows,
+12 -10
View File
@@ -16,20 +16,22 @@ func TestPack(t *testing.T) {
MarginLeft: 10,
}
spec := model.ItemSpec{SizeMM: 80, BleedMM: 2, MarginMM: 5}
// footprint = 80+4+10 = 94, cell = 94+2 = 96
// printable 280x380 -> cols=2, rows=3 -> 6
// viewport 80mm, cell = 80+2 = 82, printable 280x380 -> cols=3, rows=4 -> 12
preview := Pack(plate, spec, 2)
if preview.Columns != 2 {
t.Fatalf("columns: got %d want 2", preview.Columns)
if preview.Columns != 3 {
t.Fatalf("columns: got %d want 3", preview.Columns)
}
if preview.Rows != 3 {
t.Fatalf("rows: got %d want 3", preview.Rows)
if preview.Rows != 4 {
t.Fatalf("rows: got %d want 4", preview.Rows)
}
if preview.Count != 6 {
t.Fatalf("count: got %d want 6", preview.Count)
if preview.Count != 12 {
t.Fatalf("count: got %d want 12", preview.Count)
}
if len(preview.Positions) != 6 {
t.Fatalf("positions: got %d want 6", len(preview.Positions))
if preview.FootprintWMM != 80 {
t.Fatalf("footprint width: got %v want 80", preview.FootprintWMM)
}
if len(preview.Positions) != 12 {
t.Fatalf("positions: got %d want 12", len(preview.Positions))
}
if preview.Positions[0].XMM != 10 || preview.Positions[0].YMM != 10 {
t.Fatalf("first position: got (%v,%v)", preview.Positions[0].XMM, preview.Positions[0].YMM)