makerstash/server/services/costCalculator.js

123 lines
3.2 KiB
JavaScript

/**
* Cost Calculator Service
* Estimates filament/resin costs based on file size
*/
// Default material costs (per kg)
const DEFAULT_COSTS = {
// FDM Filaments
'pla': 15, // PLA ~$15/kg
'abs': 18, // ABS ~$18/kg
'petg': 20, // PETG ~$20/kg
'nylon': 35, // Nylon ~$35/kg
'tpu': 40, // TPU ~$40/kg
'carbon': 50, // Carbon Fiber ~$50/kg
'bamboo': 25, // Bamboo ~$25/kg
// Resin
'standard': 12, // Standard Resin ~$12/ml
'tough': 18, // Tough Resin ~$18/ml
'flexible': 20, // Flexible Resin ~$20/ml
'castable': 25, // Castable Resin ~$25/ml
};
// Density of materials (g/cm³)
const MATERIAL_DENSITY = {
// FDM Filaments
'pla': 1.24,
'abs': 1.04,
'petg': 1.27,
'nylon': 1.14,
'tpu': 1.21,
'carbon': 1.30,
'bamboo': 1.25,
// Resin
'standard': 1.15,
'tough': 1.18,
'flexible': 1.20,
'castable': 1.22,
};
/**
* Estimate material weight from file size
* Using heuristic: file size in bytes → approximate volume → weight
*
* Formula: Weight (g) = (File Size in MB) * 50 * density / material_type_factor
* This is a rough estimation since we don't have actual 3D geometry
*/
export function estimateWeight(fileSizeBytes, materialType = 'pla') {
// Convert bytes to MB
const fileSizeMB = fileSizeBytes / (1024 * 1024);
// Heuristic factor: roughly 50-70g per MB of STL/OBJ, less for compressed 3MF
// Average density is ~1.2, so we use that as baseline
const baseFactor = 55;
const density = MATERIAL_DENSITY[materialType] || 1.2;
// Estimate weight in grams
const weightGrams = fileSizeMB * baseFactor * (density / 1.2);
return Math.max(weightGrams, 1); // Minimum 1 gram
}
/**
* Calculate cost based on estimated weight and material type
*/
export function calculateCost(fileSizeBytes, materialType = 'pla', customCostPerUnit = null) {
const costPerUnit = customCostPerUnit || DEFAULT_COSTS[materialType] || DEFAULT_COSTS['pla'];
const weight = estimateWeight(fileSizeBytes, materialType);
// Convert to kg for FDM or ml for resin
const units = weight / 1000;
return {
material: materialType,
weight: Math.round(weight * 100) / 100, // grams
units: Math.round(units * 100) / 100,
costPerUnit: costPerUnit,
estimatedCost: Math.round(units * costPerUnit * 100) / 100,
confidence: 'low' // Note: This is a rough estimate
};
}
/**
* Get all available materials with their costs
*/
export function getMaterials() {
return Object.keys(DEFAULT_COSTS).map(material => ({
type: material,
costPerUnit: DEFAULT_COSTS[material],
density: MATERIAL_DENSITY[material]
}));
}
/**
* Update cost for a material
*/
export function updateMaterialCost(materialType, costPerUnit) {
if (DEFAULT_COSTS.hasOwnProperty(materialType)) {
DEFAULT_COSTS[materialType] = costPerUnit;
return true;
}
return false;
}
/**
* Batch calculate costs for multiple models
*/
export function batchCalculateCosts(models, materialType = 'pla') {
return models.map(model => ({
modelId: model.id,
name: model.name,
...calculateCost(model.file_size, materialType)
}));
}
export default {
estimateWeight,
calculateCost,
getMaterials,
updateMaterialCost,
batchCalculateCosts
};