"""Job cost and time estimation from STL geometry.""" import os # g/cm³ per material _DENSITY: dict[str, float] = { "PLA": 1.24, "PETG": 1.27, "ABS": 1.04, "ASA": 1.07, "TPU": 1.20, "Nylon": 1.14, "PC": 1.20, } _DEFAULT_DENSITY = 1.24 def estimate(volume_ccm: float, material: str | None) -> dict: """ Returns a cost/time estimate dict for one job. MATERIAL_FACTOR (env, default 0.50): Fraction of model volume that becomes actual filament. '20 % infill' in the slicer does NOT mean 20 % of volume is printed — walls, top/bottom solid layers, and shells are 100 % solid and typically dominate. Empirically ~50 % of model volume is printed for typical FDM parts (validated against Bambu Lab Studio output). PRINT_SPEED_G_PER_HOUR (env, default 32): Average material throughput in g/h. ~32 g/h matches Bambu Lab printers at normal quality; slower printers (~20 g/h) can be set here. """ vat_rate = float(os.environ.get("VAT_RATE", 19)) price_per_kg = float(os.environ.get("FILAMENT_PRICE_PER_KG", 15)) material_factor = float(os.environ.get("MATERIAL_FACTOR", 0.50)) print_speed = float(os.environ.get("PRINT_SPEED_G_PER_HOUR", 32)) density = _DENSITY.get(material or "", _DEFAULT_DENSITY) material_ccm = volume_ccm * material_factor weight_g = material_ccm * density print_minutes = round((weight_g / print_speed) * 60) filament_cost = weight_g / 1000 * price_per_kg after_misprint = filament_cost * 1.20 net_price = after_misprint * 1.30 gross_price = net_price * (1 + vat_rate / 100) return { "material_ccm": round(material_ccm, 2), "weight_g": round(weight_g, 1), "print_minutes": print_minutes, "filament_cost": round(filament_cost, 2), "net_price": round(net_price, 2), "gross_price": round(gross_price, 2), "vat_rate": vat_rate, "price_per_kg": price_per_kg, "material_factor": material_factor, "print_speed": print_speed, }