@plastichub/osr-cad
Version:
This is a CLI(CommandLineInterface) toolset to convert 3D files, using Solidworks and other software.
355 lines • 16.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.convert = exports.targets = exports.report = exports.convertFiles = exports.convertFile = exports.getBin = exports.getSlicrDir = exports.fileAsBuffer = void 0;
const path = require("path");
const __1 = require("..");
const lib_1 = require("../lib");
const osr_commons_1 = require("@plastichub/osr-commons");
const exists_1 = require("@plastichub/fs/exists");
const read_1 = require("@plastichub/fs/read");
const write_1 = require("@plastichub/fs/write");
const dir_1 = require("@plastichub/fs/dir");
const bluebird_1 = require("bluebird");
const which_1 = require("which");
const md5 = require("md5");
const index_1 = require("../lib/process/index");
const report_1 = require("../report");
const lib_2 = require("@plastichub/osr-cache/lib");
const constants_1 = require("../constants");
const fileAsBuffer = (path) => (0, read_1.sync)(path, 'buffer') || Buffer.from("-");
exports.fileAsBuffer = fileAsBuffer;
const SLIC3R_EXE = 'Slic3r-console.exe';
const clone = (obj) => {
if (null == obj || "object" != typeof obj)
return obj;
var copy = obj.constructor();
for (var attr in obj) {
if (obj.hasOwnProperty(attr))
copy[attr] = obj[attr];
}
return copy;
};
const getSlicrDir = (options) => {
const dir = path.parse((0, which_1.sync)(SLIC3R_EXE)).dir;
if ((0, exists_1.sync)(dir)) {
return dir;
}
};
exports.getSlicrDir = getSlicrDir;
const getBin = (options) => {
const dir = (0, exports.getSlicrDir)(options);
const exe = path.resolve(path.join(dir, SLIC3R_EXE));
if ((0, exists_1.sync)(exe)) {
return exe;
}
};
exports.getBin = getBin;
const toPercentString = (aNumber) => String(aNumber * 100) + '%';
const convertFile = async (file, target, onNode = () => { }, options) => {
let bin = (0, exports.getBin)(options);
if (!bin) {
__1.logger.error(`Cant find Slicr. Please register the directory in your $PATH environment variable!`);
return;
}
const getArgs = (o) => {
return [
`--output "${target}"`,
// Non-slicing actions
o.repair ? '--repair' : '',
o.cut ? '--cut' : '',
o.split ? '--split' : '',
o.info ? '--info' : '',
'--threads ' + o.threads,
// Output options
o.outputFilenameFormat ?
'--output-filename-format ' + o.outputFilenameFormat : '',
o.postProcess ? o.postProcessScripts.map(function (script) {
return '--post-process ' + script;
}).join(' ') : '',
o.exportSvg ? '--export-svg' : '',
o.merge ? '--merge' : '',
// Printer options
'--nozzle-diameter ' + o.nozzleDiameter,
'--print-center ' + o.printCenter.x + ',' + o.printCenter.y,
'--z-offset ' + o.zOffset,
'--gcode-flavor ' + o.GCodeFlavor,
o.useRelativeEDistances ? '--use-relative-e-distances ' : '',
o.useFirmwareRetraction ? '--use-firmware-retraction ' : '',
o.useVolumetricE ? '--use-volumetric-e ' : '',
o.GCodeArcs ? '--gcode-arcs' : '',
o.g0 ? '--g0' : '',
o.GCodeComments ? '--gcode-comments' : '',
'--vibration-limit ' + o.vibrationLimit,
//'--pressure-advance ' + o.pressureAdvance,
// Filament options
'--filament-diameter ' + o.filamentDiameter,
'--extrusion-multiplier ' + o.extrusionMultiplier,
'--temperature ' + o.temperature,
'--first-layer-temperature ' + o.firstLayerTemperature,
'--bed-temperature ' + o.bedTemperature,
'--first-layer-bed-temperature ' + o.firstLayerBedTemperature,
// Speed options
'--travel-speed ' + o.travelSpeed,
'--perimeter-speed ' + o.perimeterSpeed,
'--small-perimeter-speed ' + o.smallPerimeterSpeed,
'--external-perimeter-speed ' + o.externalPerimeterSpeed,
'--infill-speed ' + o.infillSpeed,
'--solid-infill-speed ' + o.solidInfillSpeed,
'--top-solid-infill-speed ' + o.topSolidInfillSpeed,
'--support-material-speed ' + o.supportMaterialSpeed,
'--support-material-interface-speed ' + o.supportMaterialInterfaceSpeed,
'--bridge-speed ' + o.bridgeSpeed,
'--gap-fill-speed ' + o.gapFillSpeed,
'--first-layer-speed ' + o.firstLayerSpeed,
// Accelerator options
'--perimeter-acceleration ' + o.perimeterAcceleration,
'--infill-acceleration ' + o.infillAcceleration,
'--bridge-acceleration ' + o.bridgeAcceleration,
'--first-layer-acceleration ' + o.firstLayerAcceleration,
'--default-acceleration ' + o.defaultAcceleration,
// Accuracy options
'--layer-height ' + o.layerHeight,
'--first-layer-height ' + o.firstLayerHeight,
'--infill-every-layers ' + o.infillEveryLayers,
'--solid-infill-every-layers ' + o.solidInfillEveryLayers,
// Print Options
'--perimeters ' + o.perimeters,
'--top-solid-layers ' + o.topSolidLayers,
'--bottom-solid-layers ' + o.bottomSolidLayers,
o.solidLayers ? '--solid-layers' : '',
'--fill-density ' + toPercentString(o.fillDensity),
'--fill-angle ' + o.fillAngle,
'--fill-pattern ' + o.fillPattern,
'--solid-fill-pattern ' + o.solidFillPattern,
o.startGcode ? '--start-gcode' : '',
o.endGcode ? '--end-gcode ' : '',
o.layerGcode ? '--layer-gcode ' : '',
o.toolchangeGcode ? '--toolchange-gcode ' : '',
'--seam-position ' + o.seamPosition,
o.externalPerimetersFirst ? '--external-perimeters-first ' : '',
o.spiralVase ? '--spiral-vase ' : '',
o.onlyRetractWhenCrossingPerimeters ?
'--only-retract-when-crossing-perimeters ' : '',
'--solid-infill-below-area ' + o.solidInfillBelowArea,
o.infillOnlyWhereNeeded ? '--infill-only-where-needed ' : '',
o.infillFirst ? '--infill-first ' : '',
// Quality options
o.extraPerimeters ? '--extra-perimeters' : '',
o.avoidCrossingPerimeters ? '--avoid-crossing-perimeters' : '',
o.thinWalls ? '--thin-walls' : '',
o.overhangs ? '--overhangs' : '',
// Support material options
o.supportMaterial ? '--support-material ' : '',
'--support-material-threshold ' + o.supportMaterialThreshold,
'--support-material-pattern ' + o.supportMaterialPattern,
'--support-material-spacing ' + o.supportMaterialSpacing,
'--support-material-angle ' + o.supportMaterialAngle,
'--support-material-interface-layers ' +
o.supportMaterialInterfaceLayers,
'--support-material-interface-spacing ' +
o.supportMaterialInterfaceSpacing,
'--raft-layers ' + o.raftLayers,
'--support-material-enforce-layers ' + o.supportMaterialEnforceLayers,
o.dontSupportBridges ? '--dont-support-bridges ' : '',
// Retraction options
'--retract-length ' + o.retractLength,
'--retract-speed ' + o.retractSpeed,
'--retract-restart-extra ' + o.retractRestartExtra,
'--retract-before-travel ' + o.retractBeforeTravel,
'--retract-lift ' + o.retractLift,
o.retractLayerChange ? '--retract-layer-change' : '',
o.wipe ? '--wipe' : '',
// Retraction options for multi-extruder setups
'--retract-length-toolchange ' + o.retractLengthToolchange,
'--retract-restart-extra-toolchange ' + o.retractRestartExtraToolchange,
// Cooling options
o.cooling ? '--cooling ' : ' ',
'--min-fan-speed ' + (o.minFanSpeed * 100),
'--max-fan-speed ' + (o.maxFanSpeed * 100),
'--bridge-fan-speed ' + (o.bridgeFanSpeed * 100),
'--fan-below-layer-time ' + o.fanBelowLayerTime,
'--slowdown-below-layer-time ' + o.slowdownBelowLayerTime,
'--min-print-speed ' + o.minPrintSpeed,
'--disable-fan-first-layers ' + o.disableFanFirstLayers,
o.fanAlwaysOn ? '--fan-always-on ' : '',
// Skirt options
'--skirts ' + o.skirts,
'--skirt-distance ' + o.skirtDistance,
'--skirt-height ' + o.skirtHeight,
'--min-skirt-length ' + o.minSkirtLength,
'--brim-width ' + o.brimWidth,
// Transform options
'--scale ' + o.scale,
'--rotate ' + o.rotate,
'--duplicate ' + o.duplicate,
'--duplicate-grid ' + o.duplicateGrid,
'--duplicate-distance ' + o.duplicateDistance,
//'--xy-size-compensation ' + o.xySizeCompensation,
// Sequential printing options
o.completeObjects ? '--complete-objects ' : '',
'--extruder-clearance-radius ' + o.extruderClearanceRadius,
'--extruder-clearance-height ' + o.extruderClearanceHeight,
// Miscellaneous options:
o.notes ? '--notes ' + o.notes : '',
'--resolution ' + o.resolution,
// '--bed-size ' + o.bedSize.width + ',' + o.bedSize.height,
// Flow options (advanced):
'--extrusion-width ' + o.extrusionWidth,
o.firstLayerExtrusionWidth ?
'--first-layer-extrusion-width ' + o.firstLayerExtrusionWidth : '',
'--perimeter-extrusion-width ' + o.perimeterExtrusionWidth,
//'--external-perimeter-extrusion-width ' +
// o.externalPerimeterExtrusionWidth,
'--infill-extrusion-width ' + o.infillExtrusionWidth,
'--solid-infill-extrusion-width ' + o.solidInfillExtrusionWidth,
'--top-infill-extrusion-width ' + o.topInfillExtrusionWidth,
'--support-material-extrusion-width ' + o.supportMaterialExtrusionWidth,
'--bridge-flow-ratio ' + o.bridgeFlowRatio,
// Multiple extruder options:
o.extruderOffset.x || o.extruderOffset.y ?
'--extruder-offset ' + o.extruderOffset.x + 'x' +
o.extruderOffset.y : '',
'--perimeter-extruder ' + o.perimeterExtruder,
'--infill-extruder ' + o.infillExtruder,
//'--solid-infill-extruder ' + o.solidInfillExtruder,
'--support-material-extruder ' + o.supportMaterialExtruder,
'--support-material-interface-extruder ' +
o.supportMaterialInterfaceExtruder,
o.oozePrevention ? '--ooze-prevention ' : '',
'--standby-temperature-delta ' + o.standbyTemperatureDelta,
`"${file}"`
];
};
const osr_cache = (0, osr_commons_1.OSR_CACHE)();
const ca_options = JSON.parse(JSON.stringify({ ...options, target, skip: null }));
const cached = await (0, lib_2.get_cached)(file, ca_options, constants_1.MODULE_NAME);
if (osr_cache && cached && options.cache !== false) {
let md5Src = md5(Buffer.from(cached));
let md5Dst = md5((0, exports.fileAsBuffer)(target));
if (!(0, exists_1.sync)(target) || md5Src !== md5Dst) {
(0, write_1.sync)(target, Buffer.from(cached));
}
onNode({
src: file,
target
});
return Promise.resolve();
}
let _target = '' + target;
let args = getArgs(options).filter((a) => !!a).filter((k) => k.indexOf('undefined') == -1);
const ret = await index_1.Helper.run((0, exports.getSlicrDir)(options), SLIC3R_EXE, args, options.debug);
if (ret && ret.code !== 0) {
__1.logger.error(`Error running Slic3r : `);
return ret;
}
if (options.log) {
(0, write_1.sync)(options.log, ret.messages.join('\n'));
}
onNode({
...ret,
src: file,
target
});
if (options.saveArgs) {
(0, write_1.sync)(options.saveArgs, `${SLIC3R_EXE} ${args.join(' ')}`);
}
if (options.saveAsProfile) {
const out = clone((0, lib_1.removeEmpty)(options));
delete out['src'];
delete out['srcInfo'];
delete out['dst'];
delete out['dstInfo'];
delete out['title'];
delete out['type'];
delete out['properties'];
delete out['oneOf'];
delete out['$0'];
delete out['_'];
delete out['skip'];
delete out['variables'];
delete out['saveAsProfile'];
delete out['saveArgs'];
delete out['profile'];
delete out['debug'];
delete out['verbose'];
delete out['log'];
(0, write_1.sync)(options.saveAsProfile, out);
}
if (osr_cache) {
options.debug && __1.logger.info('Write output to cache', _target);
await (0, lib_2.set_cached)(file, ca_options, constants_1.MODULE_NAME, (0, exports.fileAsBuffer)(_target));
}
return ret;
};
exports.convertFile = convertFile;
async function convertFiles(file, targets, onNode = () => { }, options) {
if (options.dry) {
return Promise.resolve();
}
return bluebird_1.Promise.resolve(targets).map((target) => {
return (0, exports.convertFile)(file, target, onNode, options);
}, { concurrency: 1 });
}
exports.convertFiles = convertFiles;
const report = (data, dst) => {
let report = null;
if (dst.endsWith('.md')) {
//report = reportMarkdown(data);
}
if (dst.endsWith('.csv')) {
report = (0, report_1.reportCSV)(data);
}
if (report) {
__1.logger.info(`Write report to ${dst}`);
(0, write_1.sync)(dst, report);
}
return report;
};
exports.report = report;
const targets = (f, options) => {
const srcParts = path.parse(f);
const variables = clone(options.variables);
const targets = [];
if (options.dstInfo.IS_GLOB) {
options.dstInfo.GLOB_EXTENSIONS.forEach((e) => {
variables.SRC_NAME = srcParts.name;
variables.SRC_DIR = srcParts.dir;
let targetPath = (0, __1.substitute)(options.alt, options.variables.DST_PATH, variables);
targetPath = path.resolve(targetPath.replace(options.variables.DST_FILE_EXT, '') + e);
const parts = path.parse(targetPath);
if (!(0, exists_1.sync)(parts.dir)) {
try {
(0, dir_1.sync)(parts.dir);
}
catch (e) {
if (options.debug) {
__1.logger.error(`Error creating target path ${parts.dir} for ${targetPath}`);
}
return;
}
}
targets.push(targetPath);
});
}
return targets;
};
exports.targets = targets;
async function convert(options) {
let reports = [];
const onNode = options.onNode || ((data) => reports.push(data));
options.verbose && __1.logger.info(`Convert ${options.srcInfo.FILES.length} files `);
await bluebird_1.Promise.resolve(options.srcInfo.FILES).map((f) => {
const outputs = (0, exports.targets)(f, options);
options.verbose && __1.logger.info(`Convert ${f} to `, outputs);
return convertFiles(f, outputs, onNode, options);
}, { concurrency: 1 });
if (options.report) {
const reportOutFile = (0, __1.substitute)(false, options.report, {
dst: options.srcInfo.DIR
});
options.verbose && __1.logger.info(`Write report to ${reportOutFile}`);
(0, exports.report)(reports, reportOutFile);
}
}
exports.convert = convert;
//# sourceMappingURL=slic3r.js.map