Analyse STL/3MF on upload: bounding box + volume, cached in stl_cache

- StlCache model: filename, cube_x/y/z (mm), volume_ccm
- Migration 0007: stl_cache table
- app/stl_analysis.py: trimesh-based analyse() + get_cache_map()
  - Runs immediately after upload in both /jobs and /brackets/{id}/jobs
  - Skips .gcode (no geometry), caches per filename, idempotent
- Library selector in both modals now shows dimensions and volume
- requirements: trimesh==4.5.3

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Martin Hohenberg
2026-06-18 22:04:11 +02:00
parent ccf6a64787
commit 4c7acb1c52
8 changed files with 116 additions and 5 deletions

View File

@@ -19,6 +19,7 @@ from app.models.printer_type import PrinterType
from app.models.pricing import PricingConfig
from app.models.todo import Todo
from app.stl import get_stl_dir, list_stl_files
from app.stl_analysis import analyse, get_cache_map
router = APIRouter()
templates = Jinja2Templates(directory="app/templates")
@@ -137,7 +138,8 @@ def jobs_page(request: Request, q: str = "", db: Session = Depends(get_db)):
"printers": db.query(Printer).order_by(Printer.name).all(),
"filaments": db.query(Filament).order_by(Filament.material, Filament.color).all(),
"brackets": db.query(JobBracket).order_by(JobBracket.name).all(),
"stl_files": list_stl_files(),
"stl_files": (stl_files := list_stl_files()),
"stl_cache": get_cache_map(stl_files, db),
})
@@ -156,6 +158,7 @@ async def create_job(
if stl_file and stl_file.filename:
filename = stl_file.filename
(get_stl_dir() / filename).write_bytes(await stl_file.read())
analyse(filename, db)
elif stl_select:
filename = stl_select
@@ -210,7 +213,8 @@ def bracket_detail(bracket_id: int, request: Request, db: Session = Depends(get_
"active": "brackets",
"bracket": bracket,
"filaments": db.query(Filament).order_by(Filament.material, Filament.color).all(),
"stl_files": list_stl_files(),
"stl_files": (stl_files := list_stl_files()),
"stl_cache": get_cache_map(stl_files, db),
})
@@ -228,6 +232,7 @@ async def add_jobs_to_bracket(
if stl_file and stl_file.filename:
filename = stl_file.filename
(get_stl_dir() / filename).write_bytes(await stl_file.read())
analyse(filename, db)
elif stl_select:
filename = stl_select