fix(back-end): fix 3mf calculator
Some checks failed
Build and Deploy / test-backend (push) Successful in 24s
Build and Deploy / test-frontend (push) Successful in 1m0s
Build and Deploy / build-and-push (push) Failing after 14s
Build and Deploy / deploy (push) Has been skipped

This commit is contained in:
2026-03-04 09:24:21 +01:00
parent 6eb0629136
commit db748fb649
2 changed files with 55 additions and 3 deletions

View File

@@ -146,6 +146,7 @@ public class QuoteSessionController {
Files.copy(inputStream, persistentPath, StandardCopyOption.REPLACE_EXISTING); Files.copy(inputStream, persistentPath, StandardCopyOption.REPLACE_EXISTING);
} }
Path convertedPersistentPath = null;
try { try {
// Apply Basic/Advanced Logic // Apply Basic/Advanced Logic
applyPrintSettings(settings); applyPrintSettings(settings);
@@ -183,9 +184,20 @@ public class QuoteSessionController {
if (settings.getInfillDensity() != null) processOverrides.put("sparse_infill_density", settings.getInfillDensity() + "%"); if (settings.getInfillDensity() != null) processOverrides.put("sparse_infill_density", settings.getInfillDensity() + "%");
if (settings.getInfillPattern() != null) processOverrides.put("sparse_infill_pattern", settings.getInfillPattern()); if (settings.getInfillPattern() != null) processOverrides.put("sparse_infill_pattern", settings.getInfillPattern());
Path slicerInputPath = persistentPath;
if ("3mf".equals(ext)) {
String convertedFilename = UUID.randomUUID() + "-converted.stl";
convertedPersistentPath = sessionStorageDir.resolve(convertedFilename).normalize();
if (!convertedPersistentPath.startsWith(sessionStorageDir)) {
throw new IOException("Invalid converted STL storage path");
}
slicerService.convert3mfToPersistentStl(persistentPath.toFile(), convertedPersistentPath);
slicerInputPath = convertedPersistentPath;
}
// 3. Slice (Use persistent path) // 3. Slice (Use persistent path)
PrintStats stats = slicerService.slice( PrintStats stats = slicerService.slice(
persistentPath.toFile(), slicerInputPath.toFile(),
machineProfile, machineProfile,
filamentProfile, filamentProfile,
processProfile, processProfile,
@@ -193,7 +205,7 @@ public class QuoteSessionController {
processOverrides processOverrides
); );
Optional<ModelDimensions> modelDimensions = slicerService.inspectModelDimensions(persistentPath.toFile()); Optional<ModelDimensions> modelDimensions = slicerService.inspectModelDimensions(slicerInputPath.toFile());
// 4. Calculate Quote // 4. Calculate Quote
QuoteResult result = quoteCalculator.calculate(stats, machine.getPrinterDisplayName(), selectedVariant); QuoteResult result = quoteCalculator.calculate(stats, machine.getPrinterDisplayName(), selectedVariant);
@@ -216,6 +228,9 @@ public class QuoteSessionController {
Map<String, Object> breakdown = new HashMap<>(); Map<String, Object> breakdown = new HashMap<>();
breakdown.put("machine_cost", result.getTotalPrice()); // Excludes setup fee which is at session level breakdown.put("machine_cost", result.getTotalPrice()); // Excludes setup fee which is at session level
breakdown.put("setup_fee", 0); breakdown.put("setup_fee", 0);
if (convertedPersistentPath != null) {
breakdown.put("convertedStoredPath", QUOTE_STORAGE_ROOT.relativize(convertedPersistentPath).toString());
}
item.setPricingBreakdown(breakdown); item.setPricingBreakdown(breakdown);
// Dimensions for shipping/package checks are computed server-side from the uploaded model. // Dimensions for shipping/package checks are computed server-side from the uploaded model.
@@ -237,6 +252,9 @@ public class QuoteSessionController {
} catch (Exception e) { } catch (Exception e) {
// Cleanup if failed // Cleanup if failed
Files.deleteIfExists(persistentPath); Files.deleteIfExists(persistentPath);
if (convertedPersistentPath != null) {
Files.deleteIfExists(convertedPersistentPath);
}
throw e; throw e;
} }
} }

View File

@@ -331,6 +331,31 @@ public class SlicerService {
return convertedStlPaths; return convertedStlPaths;
} }
public Path convert3mfToPersistentStl(File input3mf, Path destinationStl) throws IOException {
Path tempDir = Files.createTempDirectory("slicer_convert_");
try {
List<String> convertedPaths = convert3mfToStlInputPaths(input3mf, tempDir);
if (convertedPaths.isEmpty()) {
throw new ModelProcessingException(
"MODEL_CONVERSION_FAILED",
"Unable to process this 3MF file. Try another format or contact us directly via Request Consultation."
);
}
Path source = Path.of(convertedPaths.get(0));
Path parent = destinationStl.toAbsolutePath().normalize().getParent();
if (parent != null) {
Files.createDirectories(parent);
}
Files.copy(source, destinationStl, java.nio.file.StandardCopyOption.REPLACE_EXISTING);
return destinationStl;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IOException("Interrupted during 3MF conversion", e);
} finally {
deleteRecursively(tempDir);
}
}
private List<String> convert3mfToStlInputPaths(File input3mf, Path tempDir) throws IOException, InterruptedException { private List<String> convert3mfToStlInputPaths(File input3mf, Path tempDir) throws IOException, InterruptedException {
Path conversionOutputDir = tempDir.resolve("converted-from-3mf"); Path conversionOutputDir = tempDir.resolve("converted-from-3mf");
Files.createDirectories(conversionOutputDir); Files.createDirectories(conversionOutputDir);
@@ -378,7 +403,16 @@ public class SlicerService {
try { try {
objLog = runAssimpExport(input3mfPath, conversionOutputObjPath, tempDir.resolve("assimp-convert-obj.log")); objLog = runAssimpExport(input3mfPath, conversionOutputObjPath, tempDir.resolve("assimp-convert-obj.log"));
if (hasRenderableGeometry(convertedObj)) { if (hasRenderableGeometry(convertedObj)) {
return List.of(convertedObj.toString()); Path stlFromObj = conversionOutputDir.resolve("converted-from-obj.stl");
runAssimpExport(
convertedObj.toString(),
stlFromObj.toString(),
tempDir.resolve("assimp-convert-obj-to-stl.log")
);
if (hasRenderableGeometry(stlFromObj)) {
return List.of(stlFromObj.toString());
}
logger.warning("Assimp OBJ->STL conversion produced empty geometry.");
} }
logger.warning("Assimp OBJ conversion produced empty geometry."); logger.warning("Assimp OBJ conversion produced empty geometry.");
} catch (IOException e) { } catch (IOException e) {